visual studio odp net framework for dataaccess data c# oracle odp.net managed oracle12c

c# - odp - oracle managed data access visual studio 2017



ODP.NET Oracle.ManagedDataAcess errores aleatorios ORA-12570 (5)

Estoy intentando migrar a Oracle.ManagedDataAcess desde una versión no administrada y recibo randoms ORA-12570 TNS: error de lector de paquetes.

No sé por qué comienza este error, pero una vez que se inicia, cada solicitud subsiguiente genera el mismo error durante unos 10-30 minutos, luego vuelve a funcionar durante otros 10-30 minutos, y así sucesivamente.

Así que es un azar de fallas subsiguientes por algún tiempo y luego éxito.

Ya he probado un montón de cosas, para resumir:

El entorno:

  • Oracle.ManagedDataAcess versión 12.1.2400 (4.121.2.20150926) (nuget) (no hay ninguna referencia de gac instalada en el servidor que pueda anular la versión bin)
  • Oracle Server Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - Producción de 64 bits
  • Windows 2012 (Windows Update ok)

Comprobado:

  • Firewall: no es un problema de firewall
  • Error de máquina: el mismo problema ocurre en mi máquina, la aplicación web de Azure y una instancia de AWS EC2
  • Interferencia: No hay sniffer en ejecución, proxy transparente, etc.
  • Cifrado: no uso ningún tipo de cifrado (a menos que haya algo habilitado de forma predeterminada que no sé)
  • Cadena de conexiones: la misma cadena de conexión funciona perfectamente con la versión no administrada

Información adicional:

  • Esta es una base de datos de producción, es muy estable.
  • La aplicación está compilada para anycpu, el grupo de aplicaciones IIS está restringido a 64 bits
  • Estoy probando exactamente la misma solicitud cada vez (solo una actualización en una url de obtención de un resto ws, webapi), por lo que no está relacionado con el formato de datos

Configuración:

Servidor sqlnet.ora

SQLNET.AUTHENTICATION_SERVICES= (NTS) NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)

Aplicación web.config

<connectionStrings> <add name="XXXX" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=xxx.xxx.com)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=xxx)));User Id=xxxxx;Password=xxxxx;" /> </connectionStrings> <configSections> <section name="oracle.manageddataaccess.client" type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342" /> </configSections> <oracle.manageddataaccess.client> <version number="*"> <dataSources> <!--<dataSource alias="SampleDataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) " />--> </dataSources> <settings> <setting name="SQLNET.AUTHENTICATION_SERVICES" value="NONE"/> <!--NTS--> <setting name="sqlnet.crypto_checksum_server" value="rejected"/> <setting name="sqlnet.crypto_checksum_client" value="rejected"/> <setting name="SQLNET.ENCRYPTION_SERVER" value="rejected"/> </settings> </version> </oracle.manageddataaccess.client>

Algunas referencias:

https://community.oracle.com/thread/3634263?start=0&tstart=0

El controlador administrado de ODP.net lanza ORA-12570: Sesión de red: error de lectura de paquete inesperado

Cliente administrado de Oracle con opciones avanzadas de seguridad de Oracle

Error de ODP.NET en IIS: Sesión de red ORA-12357 Fin del archivo

ACTUALIZACIÓN 1

Después de cambiar la agrupación (como describí como una respuesta aquí), decidí publicar una versión para hacer una prueba real. Después de 1 día y los usuarios quejándose del rendimiento obtuve otro error: el valor no puede ser nulo. Nombre del parámetro: byteArray

Cambié la referencia a la versión no administrada y todo volvió a estar bien, más rápido, sin error de bytearray, mejor administración de agrupación.

Así que, por ahora, estoy renunciando a la versión administrada, tal vez vuelva a intentarlo en la próxima versión de Oracle.

Aquí algunas referencias sobre este nuevo error, como puede ver, parece otro error (aún sin respuesta).

https://community.oracle.com/thread/3676588?start=0&tstart=0

EF + ODP.NET + CLOB = El valor no puede ser nulo - Nombre del parámetro: byteArray?

Hasta ahora, razones para no usar :

  • Error de gestión de agrupación
  • CLOB null / not null bytearray errores
  • Degradación del rendimiento probablemente relacionada con la agrupación de errores

Después de deshabilitar la agrupación (Agrupación = Falso), como sugirió @ bdn02, pude confirmar que funcionó. Sin embargo, creo que debería afectar el rendimiento y me preocupaba la publicación de este código en producción sin ningún tipo de agrupación (pensé que los valores estándar estaban bien).

Así que probé muchas configuraciones y parece que de alguna manera (no está muy claro) la administración de pool de oracle estaba generando un error ORA-12570 y, después de un período de tiempo, las sesiones se cerraron y la aplicación volvió a funcionar.

Para encontrar la mejor configuración con la agrupación habilitada, creé una aplicación de prueba para iniciar 50 subprocesos (cada una haciendo 1 prueba cada 50 ms), y disminuí los valores predeterminados de la agrupación hasta que se detuvo el error. De esta manera pude obtener una configuración óptima, estable, sin errores.

Obviamente, no se aplica a todos los servidores, pero esta es la configuración final de mi cadena de conexión:

Pooling=true;Min Pool Size=1;Connection Lifetime=180;Max Pool Size=50;Incr Pool Size=5


En mi experiencia con un error similar 12570 (lector frente a escritor) solo hay una razón para este error: algo en su red está terminando las conexiones inactivas de TCP. Típicamente este es un firewall / switch administrado. Dijiste que ya habías descartado el firewall, pero no estoy seguro de cómo. Es posible que la propia db esté terminando las conexiones (script dba), pero recuerdo que es un error diferente.

Ora-12571 podría ser ligeramente diferente. Pero aún así, dado que ha identificado que el problema es el mismo, se trata de conexiones de grupo de larga data que seguiré.

Hay un par de cosas que puedes hacer:

  1. Establezca el tamaño mínimo de grupo = 0 en la cadena de conexión. Esto generalmente arregla las cosas para mí. Permite que toda la piscina se cierre cuando la aplicación está inactiva. Sin embargo, existe una pequeña posibilidad de que, si el tráfico cambia de forma violenta, el tamaño del conjunto de elementos decr. Deba aumentar para poder cerrar más rápidamente las conexiones creadas por una loca carrera.
  2. Establecer Expire_Time en sqlnet.ora. No es obvio por su nombre, esta configuración envía un paquete de problema, lo que hace que se satisfaga cualquier monitoreo de tcp inactivo. El único problema aquí es que no estoy completamente seguro de cómo establecer la configuración de sqlnet con el proveedor administrado. Supongo que sqlnet.ora puede ir en el exe dir, pero también veo algunos indicios de que puede configurarse en el .config en la forma de (vea un ejemplo similar de Wallet_override here ) porque solo está obteniendo esto en el proveedor administrado, me pregunto si su cliente no administrado sqlnet.ora ya tiene esta configuración.

Lo he visto muchas veces a lo largo de los años y la primera vez que sucedió, creé una utilidad que básicamente realiza una búsqueda binaria para determinar el tiempo de espera exacto mediante la creación de conexiones de diferentes duraciones. Si cae constantemente en el mismo tiempo de terminación, puedes adivinar que hay una configuración que está causando esto. Si es errático, entonces es posible que tenga algún tipo de descamación de la infraestructura.

Desafortunadamente, lo creé como una aplicación ac # forms, así que pegué el código del formulario y el código del diseñador a continuación:

Form1.cs:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Oracle.ManagedDataAccess.Client; namespace TimeoutTest { public partial class Form1 : Form { List<TestConnection> connections; Int32 connectionCount; Int32 multiplier; Int32 initialConnectionWait; TestConnection controlConnection = null; public Form1() { InitializeComponent(); } private void BtStart_Click(object sender, EventArgs e) { connectionCount = Int32.Parse(InConnections.Text); multiplier = Int32.Parse(InMultiplier.Text); initialConnectionWait = Int32.Parse(InInitialWait.Text); DisplayMessage("Starting control connection/r/n"); controlConnection = new TestConnection(); controlConnection.ErrorOccured += new EventHandler(controlConnection_ErrorOccured); controlConnection.IsControlConnection = true; controlConnection.StartTest(2); connections = new List<TestConnection>(); DisplayMessage("Spinning up {0} connections.../r/n", connectionCount); for (int i = 0, idleTime=initialConnectionWait; i < connectionCount; i++, idleTime*=multiplier) { TestConnection connection = new TestConnection(); connection.Notified += new TestConnection.NotificationEventHandler(connection_Notified); connection.ErrorOccured += new EventHandler(connection_ErrorOccured); connection.TestCompleted += new EventHandler(connection_TestCompleted); connection.StartTest(idleTime); connections.Add(connection); } DisplayMessage(""); } void controlConnection_ErrorOccured(object sender, EventArgs e) { DisplayMessage("/r/nControl connection error, aborting!!!"); BtCancel_Click(this, EventArgs.Empty); } void connection_TestCompleted(object sender, EventArgs e) { TestConnection currentConnection = (TestConnection)sender; if (currentConnection == connections.Last()) DisplayMessage("/r/nAll tests complete. Done"); } void connection_ErrorOccured(object sender, EventArgs e) { //stop any active connection. foreach(TestConnection tc in connections) { tc.CompletionTimer.Enabled=false; } TestConnection currentConnection = (TestConnection)sender; Int32 upperTime = currentConnection.IdleTime; Int32 lowerTime = 0; Int32 index = connections.IndexOf(currentConnection); //if this is not the first connection... if(index > 0) { //...then set the lower time based on the previous connection lowerTime = connections[index-1].IdleTime; } //get the difference between the lower and upper as the new range to work on Int32 range = upperTime - lowerTime; //divide the range over the number of connections to get the new interval Int32 interval = range / this.connectionCount; connections.Clear(); //if the interval is too small try to reduce the number of connections while (interval < 2 && this.connectionCount > 2) { this.connectionCount--; DisplayMessage("/r/nConnections too high for current resolution. Reducing to {0} connections.", this.connectionCount); interval = range / this.connectionCount; } if(interval < 2) { DisplayMessage("/r/nResolution cannot be increased. Done."); } else { DisplayMessage("/r/nRestarting test with min:{0}, max{1}, resolution{2}.", lowerTime, upperTime, interval); //create the new connections for (int i = connectionCount-1, idleTime = upperTime-interval; i >= 0; i--, idleTime-=interval) { TestConnection connection = new TestConnection(); connection.Notified += new TestConnection.NotificationEventHandler(connection_Notified); connection.ErrorOccured += new EventHandler(connection_ErrorOccured); connection.TestCompleted += new EventHandler(connection_TestCompleted); connection.StartTest(idleTime); connections.Insert(0,connection); } this.connectionCount = connections.Count; } } private void BtCancel_Click(object sender, EventArgs e) { //stop any active connection. foreach (TestConnection tc in connections) { tc.CompletionTimer.Enabled = false; tc.Command.Connection.Close(); } DisplayMessage("Stopped running tests."); } void connection_Notified(object o, Form1.TestConnection.NotificationEventArgs e) { DisplayMessage(e.Message); } private void DisplayMessage(String message) { DisplayMessage("{0}", message); } private void DisplayMessage(String message, params Object[] args) { OutStatus.AppendText(String.Format(message, args) + "/r/n"); } public class TestConnection { public Boolean IsControlConnection { get; set; } public OracleCommand Command { get; private set; } public Timer CompletionTimer { get; private set; } public String ConnectionId { get; private set; } public Int32 IdleTime { get { return CompletionTimer.Interval / 1000; } set { CompletionTimer.Interval = value * 1000; } } #region Events and Delegates public event EventHandler ErrorOccured; public event EventHandler TestCompleted; public class NotificationEventArgs : EventArgs { public NotificationEventArgs(String message) { this.Message = message; } public String Message { get; set; } } public delegate void NotificationEventHandler(object o, NotificationEventArgs e); public event NotificationEventHandler Notified; private void Notify(String message) { if (Notified != null) { Notified(this, new NotificationEventArgs(message)); } } public void Notify(String format, params object[] args) { this.Notify(String.Format(format, args)); } #endregion public TestConnection() { CompletionTimer = new Timer(); CompletionTimer.Tick += new EventHandler(CompleteTest); Command = new OracleCommand( "select ''saddr:'' || saddr || ''-sid:'' || sid || ''-serial#:'' || serial# || ''-audsid:'' || audsid || ''-paddr:'' || paddr || ''-module:'' || module from gv$session where audsid=Userenv(''SESSIONID'')"); Command.Connection = new OracleConnection(Configuration.OracleConnectionString); } public String StartTest(Int32 idleTime) { Command.Connection.Open(); ConnectionId = (String)Command.ExecuteScalar(); Notify("Started test with idle time={0}, id={1}.", idleTime, ConnectionId); IdleTime = idleTime; CompletionTimer.Enabled = true; return ConnectionId; } private void CompleteTest(object sender, EventArgs e) { if (!IsControlConnection) CompletionTimer.Enabled = false; try { Command.ExecuteScalar(); Notify("Test complete on connection with idle time={0}, id={1}.", IdleTime, ConnectionId); if (TestCompleted != null) TestCompleted(this, EventArgs.Empty); } catch (OracleException ex) { if (ex.Number == 12571) { if (ErrorOccured != null) { Notify("Found error on connection with idle time={0}, id={1}.", IdleTime, ConnectionId); ErrorOccured(this, EventArgs.Empty); } } else { Notify("Unknown error occured on connection with timeout {0}, Error: {1}, /r/n{2}",(IdleTime).ToString(), ex, ConnectionId); } } catch (Exception ex) { Notify("Unknown error occured on connection with timeout {0}, Error: {1}, /r/n{2}", (IdleTime).ToString(), ex, ConnectionId); } finally { if(!IsControlConnection) Command.Connection.Close(); } } } private void InConnections_TextChanged(object sender, EventArgs e) { Int32.TryParse(InConnections.Text,out connectionCount); Int32.TryParse(InMultiplier.Text,out multiplier); Int32.TryParse(InInitialWait.Text, out initialConnectionWait); OutLongestConnection.Text = (Math.Pow(multiplier,connectionCount-1) * initialConnectionWait).ToString(); } private void Form1_Load(object sender, EventArgs e) { InConnections_TextChanged(this, EventArgs.Empty); } } }

Form1.designer.cs:

namespace TimeoutTest { partial class Form1 { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.BtStart = new System.Windows.Forms.Button(); this.OutStatus = new System.Windows.Forms.TextBox(); this.InConnections = new System.Windows.Forms.MaskedTextBox(); this.label1 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.InInitialWait = new System.Windows.Forms.MaskedTextBox(); this.InMultiplier = new System.Windows.Forms.MaskedTextBox(); this.label2 = new System.Windows.Forms.Label(); this.BtCancel = new System.Windows.Forms.Button(); this.label4 = new System.Windows.Forms.Label(); this.OutLongestConnection = new System.Windows.Forms.Label(); this.SuspendLayout(); // // BtStart // this.BtStart.Location = new System.Drawing.Point(13, 394); this.BtStart.Name = "BtStart"; this.BtStart.Size = new System.Drawing.Size(75, 23); this.BtStart.TabIndex = 0; this.BtStart.Text = "Start"; this.BtStart.UseVisualStyleBackColor = true; this.BtStart.Click += new System.EventHandler(this.BtStart_Click); // // OutStatus // this.OutStatus.Location = new System.Drawing.Point(13, 13); this.OutStatus.Multiline = true; this.OutStatus.Name = "OutStatus"; this.OutStatus.ReadOnly = true; this.OutStatus.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.OutStatus.Size = new System.Drawing.Size(766, 375); this.OutStatus.TabIndex = 1; // // InConnections // this.InConnections.Location = new System.Drawing.Point(180, 397); this.InConnections.Mask = "00"; this.InConnections.Name = "InConnections"; this.InConnections.Size = new System.Drawing.Size(22, 20); this.InConnections.TabIndex = 2; this.InConnections.Text = "10"; this.InConnections.TextChanged += new System.EventHandler(this.InConnections_TextChanged); // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(108, 400); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(66, 13); this.label1.TabIndex = 3; this.label1.Text = "Connections"; // // label3 // this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(289, 399); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(113, 13); this.label3.TabIndex = 5; this.label3.Text = "Initial Connection Wait"; // // InInitialWait // this.InInitialWait.Location = new System.Drawing.Point(408, 396); this.InInitialWait.Mask = "00"; this.InInitialWait.Name = "InInitialWait"; this.InInitialWait.Size = new System.Drawing.Size(21, 20); this.InInitialWait.TabIndex = 4; this.InInitialWait.Text = "60"; this.InInitialWait.TextChanged += new System.EventHandler(this.InConnections_TextChanged); // // InMultiplier // this.InMultiplier.Location = new System.Drawing.Point(262, 396); this.InMultiplier.Mask = "0"; this.InMultiplier.Name = "InMultiplier"; this.InMultiplier.Size = new System.Drawing.Size(21, 20); this.InMultiplier.TabIndex = 2; this.InMultiplier.Text = "2"; this.InMultiplier.TextChanged += new System.EventHandler(this.InConnections_TextChanged); // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(208, 400); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(48, 13); this.label2.TabIndex = 3; this.label2.Text = "Multiplier"; // // BtCancel // this.BtCancel.Location = new System.Drawing.Point(13, 436); this.BtCancel.Name = "BtCancel"; this.BtCancel.Size = new System.Drawing.Size(75, 23); this.BtCancel.TabIndex = 6; this.BtCancel.Text = "Cancel"; this.BtCancel.UseVisualStyleBackColor = true; this.BtCancel.Click += new System.EventHandler(this.BtCancel_Click); // // label4 // this.label4.AutoSize = true; this.label4.Location = new System.Drawing.Point(451, 399); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(102, 13); this.label4.TabIndex = 7; this.label4.Text = "Longest Connection"; // // OutLongestConnection // this.OutLongestConnection.AutoSize = true; this.OutLongestConnection.Location = new System.Drawing.Point(559, 399); this.OutLongestConnection.Name = "OutLongestConnection"; this.OutLongestConnection.Size = new System.Drawing.Size(102, 13); this.OutLongestConnection.TabIndex = 8; this.OutLongestConnection.Text = "Longest Connection"; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(791, 582); this.Controls.Add(this.OutLongestConnection); this.Controls.Add(this.label4); this.Controls.Add(this.BtCancel); this.Controls.Add(this.label3); this.Controls.Add(this.InInitialWait); this.Controls.Add(this.label2); this.Controls.Add(this.InMultiplier); this.Controls.Add(this.label1); this.Controls.Add(this.InConnections); this.Controls.Add(this.OutStatus); this.Controls.Add(this.BtStart); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Button BtStart; private System.Windows.Forms.TextBox OutStatus; private System.Windows.Forms.MaskedTextBox InConnections; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label3; private System.Windows.Forms.MaskedTextBox InInitialWait; private System.Windows.Forms.MaskedTextBox InMultiplier; private System.Windows.Forms.Label label2; private System.Windows.Forms.Button BtCancel; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label OutLongestConnection; } }


Encontré este mismo error intermitente al usar SQL Server Reporting Services 2016 con ODAC 12c versión 4:

Error: An error has occurred during report processing. (rsProcessingAborted) Query execution failed for dataset ''TermPrompt''. (rsErrorExecutingCommand) ORA-12570: Network Session: Unexpected packet read error ORA-12570: Network Session: Unexpected packet read error ORA-12537: Network Session: End of file

Agregar el parámetro de agrupación Data Source="myOracleDB";Pooling="false" a la fuente de datos de Oracle en SSRS resolvió el problema por completo.

Una re-ejecución inmediata del informe funciona bien.

Me doy cuenta de que hay problemas potenciales de rendimiento al crear una nueva conexión cada vez en lugar de usar el grupo, pero hasta que Oracle solucione esto, no quiero que mis usuarios encuentren este error.


Estaba recibiendo este error en una excepción de la aplicación. No hubo más detalles útiles en la excepción interna. Cambiar las opciones de agrupación no solucionó el problema, ni tampoco desactivó la agrupación. Una vez que se habilitó el rastreo, mostró un error diferente " ORA-12537 final de la sesión de red del archivo " en el archivo de rastreo (no se propagó a la excepción de la aplicación). Ese hilo sugiere que una versión antigua del controlador oracle es la culpable. Lo verifiqué y estaba usando la versión de 2014. La actualización a la versión 2017 / 12.2c / 12.2.0.1.0 resolvió el problema.


Te doy un script de powershell que uso para verificar la conectividad de la base de datos. $baselogpath = "" $filesuffix = "_GetDBConnection" $dbuser ="" $dbpassword ="" $dbalias = ""; $command = new-Object Oracle.DataAccess.Client.OracleCommand($queryString, $connection); $connection.Open(); $count = $command.ExecuteScalar(); $connection.Close();
$message = "Records found: " + $count; $esito = "OK"; } Catch { $message = $_.Exception.Message; $esito = "KO"; } $now = Get-Date $filename = $baselogpath + $now.Year + $now.Month.Tostring("00") + $now.Day.Tostring("00") + $filesuffix + ".log" if (!(Test-Path($filename))) { $fileheader = "Time Esito, Elapsed, Message" $fileheader > $filename } $Time.Stop(); $Elapsed = $Time.Elapsed; $row = $now.Hour.toString("00") + ":" + $now.Minute.toString("00") + ":" + $now.Second.toString("00") + " " + $esito + "," + $Elapsed.Hours.toString("00") + ":" + $Elapsed.Minutes.toString("00") + ":" + $Elapsed.Seconds.toString("00") + "," + $message; $row >> $filename

¿Puede intentar programar este script cada minuto, utilizando la versión administrada de Oracle administrada dll? Comprendería si el problema está solo en la aplicación web o si Oracle está relacionado con el controlador. Si desea realizar una prueba avanzada, puede programar una copia de este script que utilice la versión no administrada de oracle.dataaccess.

Buena suerte