0

我编写了一个 C# 应用程序,它与部署在另一台机器上的 (ASMX) Web 服务进行通信。Web 服务连接到位于第三层的后端数据库并对其执行操作。

应用程序中的所有数据库操作都是从名为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.NET
C# 4
SOAP 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;
    }
}
4

2 回答 2

1

我的第一个想法是这是一个提供商问题,尤其是名称解析。确保 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>

关于“连接已重置”,了解您遇到的错误会有所帮助。它可能是终止旧连接的 DBA 作业,应该为服务帐户关闭或最大化旧连接。您可以/应该设置 min pool size=0,这最终将允许终止所有连接。如果您的流量非常“尖峰”,您可能没有太多选择来设置 Validate Connection = true、禁用池或处理手动打开陈旧连接的错误。有关更多信息,请参阅有关连接池的 odp.net 文档

于 2013-04-04T19:25:15.833 回答
0

另一件事是连接会在几分钟后重置。我怎样才能保持连接活跃?

如果您谈论的是客户端和 Web 服务器之间的连接,那么您不会。ASMX SOAP 服务不是这样工作的。它创建一个连接,发出请求,然后关闭它。您可以将相同的服务对象保留一段时间,但即使您这样做,它也总是会建立新的连接。(因为我倾向于相当频繁地丢弃服务对象,并且只有一种方法可以在需要时获取新对象。)

如果您正在谈论数据库连接......那么您的代码并没有试图保持连接打开。它在方法调用的上下文中创建连接。它会创建它,使用它,然后在方法结束时让它消失。您可以通过启用连接池来保持一些连接打开(请参阅文档),这样当您的代码尝试建立连接时,数据库将打开一个连接以加快速度。

请注意,有些评论是完全正确的。您的连接应该在 using 语句中创建:

using (OracleConnection SQLConnection = new OracleConnection(string.Format(oracleConnection, host, port, database, username, password))) {
// do stuff
}

这将确保它被正确处理,并在下次需要时使连接再次可用于连接池。在您的应用程序代码中,您将打开/关闭连接,但实际上它们将在服务器和数据库之间自动保持打开状态(ODP.net 处理它)。

问题是第一次连接到数据库总是失败。因此,我需要重新运行应用程序以获得部署应用程序时无法接受的连接。

数据库失败时会出现什么错误?只是服务超时,还是存在数据库错误?如果只是超时,已知 ODP.net 在某些情况下首次加载需要一段时间。另一种可能性是,由于您让客户端发送连接信息,因此它可能在第一次请求时发送了错误信息。

于 2013-04-04T19:25:09.523 回答