ASMX webservice第一次连接ORACLE数据库时超时
本文关键字:数据库 超时 ORACLE 连接 webservice 第一次 ASMX | 更新日期: 2023-09-27 18:07:28
我写了一个c#应用程序,它与部署在另一台机器上的(ASMX) web服务通信。webservice连接到位于第三层的后端数据库并对其执行操作。
应用程序中的所有DB操作都是从一个名为DataLayerFunctor
的静态类调用的。下面是该类的一个片段:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebserviceTest.DataLayer;
using WebserviceTest.SecurityLayer;
using SettingsAlias = WebserviceTest.Properties;
namespace WebserviceTest
{
public static class DataLayerFunctor
{
public static MyWebserviceReference.Service1 myWebService;
private static string HOST = "192.168.1.100";
private static string PORT = "1521";
private static string DATABASE = "orcl";
private static string USERNAME = "MY_USER";
private static string PASSWORD = "123";
private static string ORACLE_CONNECTION_STRING = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1})))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME={2})));Users Id={3};Password={4};";
public static List<UserGroup> UserGroupsList { get; set; }
public static List<Role> RolesList { get; set; }
public static Dictionary<UserGroup,Role> GroupsToRoles { get; set; }
static DataLayerFunctor()
{
HOST = CryptoServices.DecryptText(SettingsAlias.Settings.Default.HOST,CryptoServices.DEFAULT_KEY) ?? HOST;
PORT = CryptoServices.DecryptText(SettingsAlias.Settings.Default.PORT,CryptoServices.DEFAULT_KEY )?? PORT;
DATABASE = CryptoServices.DecryptText(SettingsAlias.Settings.Default.DATABASE,CryptoServices.DEFAULT_KEY) ?? DATABASE;
USERNAME = CryptoServices.DecryptText(SettingsAlias.Settings.Default.USER_NAME,CryptoServices.DEFAULT_KEY) ?? USERNAME;
PASSWORD = CryptoServices.DecryptText(SettingsAlias.Settings.Default.PASSWORD,CryptoServices.DEFAULT_KEY) ?? PASSWORD;
ORACLE_CONNECTION_STRING = SettingsAlias.Settings.Default.ORACLE_CONNECTION_STRING ?? ORACLE_CONNECTION_STRING;
HOST = "192.168.1.6";
PORT = "1521";
DATABASE = "orcl";
USERNAME = "ALAMAL_BANK";
PASSWORD = "123";
myWebService = new MyWebserviceReference.Service1();
myWebService.Url = "http://192.168.1.6/MyWebservice/Service1.asmx";
//myWebService.Url = CryptoServices.DecryptText(SettingsAlias.Settings.Default.WebserviceURL,CryptoServices.DEFAULT_KEY);
myWebService.Timeout = 36000;
//Load enumeration tables
LoadGroupsToRoles();
}
public static void LoadGroupsToRoles() {
string query = "SELECT * FROM GROUPS_TO_ROLES";
DataTable groupsToRoles = myWebService.GetTableParamOracle(query, HOST, PORT, DATABASE, USERNAME, PASSWORD);
GroupsToRoles = new Dictionary<UserGroup, Role>();
foreach (DataRow groupsToRolesRow in groupsToRoles.Rows)
{
Role role = RolesList.First((i) => i.RoleId == groupsToRolesRow["ROLE_ID_FK"] as long?);
UserGroup userGroup = UserGroupsList.First((i) => i.GroupId == groupsToRolesRow["GROUP_ID_FK"] as long?);
GroupsToRoles.Add(userGroup, role);
}
}
}
}
问题是第一次连接数据库总是失败。所以,我需要重新运行应用程序,以获得连接,这是不可接受的应用程序部署时。另一件事是,连接会在几分钟后重置。我怎样才能保持联系?
我正在使用:
ORACLE 11g DB
ODP。净
c# 4
SOAP的Webservice
Webservice代码:
public class Service1 : System.Web.Services.WebService
{
logger.LogCreator _log = new logger.LogCreator(@"C:'GDW_logs");
public static long DataTableCounter = 1;
string oracleConnection = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1})))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME={2})));User Id={3};Password={4};";
[WebMethod]
public DataTable GetTableParamOracle(string sqltext, string host, string port, string database, string username, string password)
{
OracleConnection SQLConnection = new OracleConnection(string.Format(oracleConnection, host, port, database, username, password));
OracleDataAdapter dad = new OracleDataAdapter(sqltext, SQLConnection);
DataTable dtb = new DataTable("DataTable" + (DataTableCounter++));
SQLConnection.Open();
try
{
dad.Fill(dtb);
}
catch (Exception ex)
{
_log.WriteLine(ex.Message);
}
finally
{
SQLConnection.Close();
}
return dtb;
}
}
我的第一个想法是这是提供者的问题,特别是名称解析。确保GetTableParamOracle方法的"host"参数是完全限定的。例如,"myoracleinstance.mydomain.org"而不仅仅是"myoracleinstance"。
您可以通过确保在tnsnames中存在此实例的别名来隔离该问题。Ora和使用tnsping进行测试。第一个ping返回的速度会比其他的慢。
如果这似乎不是问题,那么您可能需要跟踪提供者,看看您是否可以识别挂起的呼叫部分:
<oracle.dataaccess.client>
<settings>
<add name="TraceFileName" value="c:'temp'odpnet1.trc"/>
<add name="TraceLevel" value="63"/>
</settings>
</oracle.dataaccess.client>
关于"connection is reset",这将有助于知道你得到的是哪个错误。它可能是一个终止旧连接的DBA作业,对于服务帐户,旧连接应该关闭或最大化。您可以/应该将最小池大小设置为0,这将最终允许终止所有连接。如果你有非常"spikey"的流量,你可能没有太多的选择,要么设置Validate Connection = true,禁用池,或者手动处理打开过时连接的错误。关于连接池的更多信息,请参阅odp.net文档。
另一件事是连接在几分钟后重置。我怎样才能保持联系?
如果你在谈论客户端和web服务器之间的连接,你不需要。ASMX SOAP服务不是这样工作的。它创建一个连接,发出请求,然后关闭它。您可以将相同的服务对象保留一段时间,但即使您这样做了,它也总是会建立新的连接。(正因为如此,我倾向于相当频繁地丢弃服务对象,只在需要的时候有一个方法来获取新的服务对象。)
如果你说的是数据库连接…你的代码并没有试图保持一个打开的连接。它在方法调用的上下文中创建了一个连接。它会创建它,使用它,然后在方法结束时让它消失。您可以通过启用连接池来保持一些连接打开(请参阅文档),这样当您的代码试图建立连接时,数据库将已经打开一个连接以加快速度。
注意有些注释是完全正确的。您的连接应该在using语句中创建:
using (OracleConnection SQLConnection = new OracleConnection(string.Format(oracleConnection, host, port, database, username, password))) {
// do stuff
}
这将确保正确地处理它,并使连接在下次需要时再次对连接池可用。在您的应用程序代码中,您将打开/关闭连接,但实际上它们将自动保持服务器和数据库之间的打开状态(ODP.net处理它)。
问题是第一次连接数据库总是失败。因此,我需要重新运行应用程序来获得连接,这是不可接受的当部署应用程序时。
数据库失败时给出的错误是什么?是服务超时,还是有数据库错误?如果只是超时,那么在某些情况下,ODP.net第一次加载需要一段时间。另一种可能性是,由于您让客户端发送连接信息,它可能在第一次请求时发送错误的内容。