C# 到ORACLE DB的ASMX webservice在第一次连接时超时
我已经编写了一个C#应用程序,它与另一台机器上部署的(ASMX)Web服务进行通信。webservice连接到位于第三层的后端数据库并对其执行操作 应用程序中的所有DB操作都是从名为C# 到ORACLE DB的ASMX webservice在第一次连接时超时,c#,web-services,oracle,asmx,odp.net,C#,Web Services,Oracle,Asmx,Odp.net,我已经编写了一个C#应用程序,它与另一台机器上部署的(ASMX)Web服务进行通信。webservice连接到位于第三层的后端数据库并对其执行操作 应用程序中的所有DB操作都是从名为DataLayerFunctor的静态类调用的。下面是该类的一个片段: using System; using System.Collections.Generic; using System.Linq; using System.Text; using WebserviceTest.DataLayer; using
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);
}
}
}
}
另一件事是连接在几分钟后被重置。
我怎样才能保持连接
如果您谈论的是客户机和web服务器之间的连接,那么您不需要。ASMX SOAP服务不是这样工作的。它创建连接、发出请求并关闭连接。您可以将同一个服务对象保留一段时间,但即使您这样做,它也总是在建立新的连接。(因此,我倾向于相当频繁地丢弃服务对象,并在需要时有一个方法来获取一个新的服务对象。)
如果你说的是数据库连接。。。您的代码没有试图保持连接打开。它在方法调用的上下文中创建连接。它将创建它,使用它,然后在方法结束时让它消失。您可以通过启用连接池()来保持某些连接处于打开状态,这样当您的代码尝试建立连接时,数据库将已经有一个连接处于打开状态,以加快连接速度
请注意,有些评论是完全正确的。应在using语句中创建连接:
using (OracleConnection SQLConnection = new OracleConnection(string.Format(oracleConnection, host, port, database, username, password))) {
// do stuff
}
这将确保正确处理该连接,并使连接池在下次需要时再次可用。在应用程序代码中,您将打开/关闭连接,但事实上,它们将在服务器和数据库之间自动保持打开状态(ODP.net处理它)
问题是第一次连接到数据库总是失败。
因此,我需要重新运行应用程序以获得无法接受的连接
部署应用程序时
数据库失败时会出现什么错误?这只是服务超时,还是数据库出错?如果只是一个超时,那么在某些情况下,ODP.net第一次加载会花费一些时间。另一种可能性是,由于您让客户端发送连接信息,它可能在第一次请求时发送了错误的内容。我的第一个想法是这是一个提供商问题,特别是名称解析。确保GetTableParamOracle方法的“主机”参数是完全限定的。例如,“myoracleinstance.mydomain.org”,而不仅仅是“myoracleinstance” 您可以通过确保tnsnames.ora中存在此实例的别名并使用tnsping进行测试来隔离问题。第一个ping将比其他ping返回得慢 如果这似乎不是问题所在,那么您可能希望跟踪提供商,看看是否可以识别挂断的呼叫部分:
<oracle.dataaccess.client>
<settings>
<add name="TraceFileName" value="c:\temp\odpnet1.trc"/>
<add name="TraceLevel" value="63"/>
</settings>
</oracle.dataaccess.client>
更多信息。ASMX是一项遗留技术,不应用于新的开发。WCF应用于web服务客户端和服务器的所有新开发。一个提示:Microsoft已停用MSDN上的。您可以从该服务发布代码吗?客户端代码没有告诉我们您在用Oracle做什么。@Tridus我已经从Web服务中为所用的方法添加了一个片段。也就是说,GetTableParamOracle。@John Saunders,我同意,但我得到了项目的原样。我的上司仍然坚持旧技术。谢谢。1)连接和数据适配器应位于使用
块的中。2) 如果你想知道发生了什么,不要只记录ex.Message
。日志例如ToString()
。3) 打电话的人怎么知道有异常?如果DataTable
被部分填充,那么会引发异常吗?您将返回部分数据表
。您最好添加throw在日志调用之后,调用方将至少收到一个异常。它超时。连接需要一段时间,然后连接失败。我再次运行它,它成功了。只要我进行连续操作,它就会正常工作,但一旦我停止,它就会再次超时。如果我运行该程序并连续对数据库进行操作,它就可以正常工作。但是,如果我在进行另一个操作之前等待一段时间,它将超时。这听起来像是我见过的一些人遇到的问题,出于某种原因,最初加载ODP.net需要很长时间。我真的很确定如何解决这个问题,因为我从来不会花那么长时间。你的主机名完全合格吗?我相信默认的OracleConnection.ConnectionTimeout是15秒,上次我遇到这个问题时,初始dns解析花了17秒。
<oracle.dataaccess.client>
<settings>
<add name="TraceFileName" value="c:\temp\odpnet1.trc"/>
<add name="TraceLevel" value="63"/>
</settings>
</oracle.dataaccess.client>