2013-04-04 29 views
0

我写了一个C#应用程序,它与部署在另一台机器上的(ASMX)web服务进行通信。 webservice连接到位于第三层的后端数据库并对其执行操作。ASMX webservice到ORACLE 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数据库
ODP.NET
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; 
    } 
} 
+0

ASMX是一项传统技术,不应该用于新开发。 WCF应该用于Web服务客户端和服务器的所有新开发。一个暗示:微软已经在MSDN上退役了[ASMX Forum](http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/threads)。 – 2013-04-04 14:32:49

+0

你可以发布服务中的代码吗?客户端代码没有告诉我们你在用Oracle做什么。 – Tridus 2013-04-04 14:34:19

+0

@Tridus我为webservice添加了一个用于所用方法的片段。即,GetTableParamOracle。 – 2013-04-04 14:47:52

回答

0

的另一件事是连接几分钟后重置。 如何保持连接活着?

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

如果您正在讨论数据库连接...以及您的代码不是'试图保持连接打开。它在方法调用的上下文中创建连接。它会创建它,使用它,然后在方法结束时让它消失。您可以通过启用连接池(see the documentation)来保持一些连接打开,并且以这种方式,当您的代码尝试建立连接时,数据库已经打开一个连接以加速连接。

请注意,一些评论是完全正确的。你的连接应该using语句内创建:

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

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

问题是首次连接到数据库总是失败。 因此,我需要重新运行应用程序才能获得部署应用程序时不可接受的连接 。

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

+0

它超时。这需要一段时间,然后连接失败。我再次运行它并成功。只要我连续操作,它会正常工作,但只要我停止它将再次超时。如果我运行该程序并以连续的方式在数据库上执行操作,则可以正常工作。但如果我在进行另一次操作之前等了一段时间,它会超时。 – 2013-04-04 20:41:21

+0

这听起来像我看到有些人在某个原因需要很长时间才能初始加载ODP.net的问题。我确实知道如何解决这个问题,因为它对我来说从不需要那么长时间。 – Tridus 2013-04-05 11:04:44

1

我的第一个想法是这是一个提供者问题,特别是名称解析。确保GetTableParamOracle方法的“主机”参数完全合格。即,“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> 

“连接被重置“,这将有助于知道你正在得到哪个错误。这可能是一个DBA作业,它将终止旧服务帐户应关闭或最大化的连接。您可以/应该设置最小池大小= 0,这将最终允许终止所有连接。如果您拥有非常'spikey'的流量,您可能没有多少选择来设置Validate Connection = true,禁用池或者手动打开陈旧连接来处理错误。有关更多信息,请参阅odp.net documentation on connection pooling

+0

这是一个超时错误。 – 2013-04-04 20:50:45

+0

您的主机名是否完全合格?我相信默认的OracleConnection.ConnectionTimeout是15秒,而我最后一次遇到这个问题时,初始dns解析耗时17秒。 – 2013-04-04 21:30:07