You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于WCF的客户端-服务器聊天应用Npgsql连接未打开问题求助

WCF聊天应用PostgreSQL连接问题排查与解决

问题描述

开发基于WCF的客户端-服务器聊天应用,使用与其他项目相同的PostgreSQL连接代码,但注册功能无法正常运行,清理Npgsql连接池无效。

客户端代码

private void bReg_Click(object sender, RoutedEventArgs e)
{
    client = new ServiceChatClient(new System.ServiceModel.InstanceContext(this));
    string response = client.Registration(tbUserName.Text,tbPassword.Text);
    MessageBox.Show(response);
    string[] responseSub = response.Split('#');
    if (responseSub[1] == string.Empty)
    {
        MessageBox.Show(responseSub[0]);
    }
    else
    {
        MessageBox.Show(responseSub[0]);
    }
}

服务端ServiceChat代码

连接字符串与全局变量

string connstring = String.Format("Server={0};Port={1};" + "User ID = {2};Password={3};Database={4};", "localhost", "5432", "postgres", "mypass", "users");
public NpgsqlCommand cmd;
public string sql = null;

注册方法

public string Registration(string username, string password)
{
    try 
    {
        NpgsqlConnection conn = new NpgsqlConnection(connstring);
        conn.Open();
        sql = @"SELECT * FROM users where username = :username";
        NpgsqlCommand cmd = new NpgsqlCommand(sql, conn);
        cmd.Parameters.AddWithValue(":username", username);
        int result = Convert.ToInt32(cmd.ExecuteScalar());
        if (result == 0)
        {
            sql = ("INSERT INTO USERS (username,password) VALUES (:username,:password)");
            cmd = new NpgsqlCommand(sql, conn);
            if (password.Length >= 4 && username.Length > 0 && password.Length <= 128 &&     
                username.Length <= 128 && !password.Contains(' '))
            {
                cmd.Parameters.AddWithValue("username", username);
                cmd.Parameters.AddWithValue("password", GetMD5(password));
                cmd.ExecuteNonQuery();
                conn.Close();
                return "Registration completed successfully#OK";
            }
            else
            {
                conn.Close();
                return "Invalid username or password#";
            }
        }
        else
        {
            conn.Close();
            return "A user with the same username already exists#";
        }
    } 
    catch (Exception ex)
    {
        string error = string.Format("Error:{0} что-то пошло не так#", ex); 
        return error;
    }
}

核心问题与修复方案

1. ExecuteScalar使用错误

原代码中SELECT * FROM users where username = :username配合ExecuteScalar(),当用户不存在时,ExecuteScalar()返回null,执行Convert.ToInt32(null)会直接抛出InvalidCastException,进入catch块。

修复:改为查询用户数量,确保返回数值类型:

sql = @"SELECT COUNT(*) FROM users where username = :username";

2. 数据库资源未正确释放

原代码手动调用conn.Close(),但如果中间抛出异常,连接可能无法关闭,导致连接池耗尽。应使用using语句自动释放连接和命令:

try 
{
    using (NpgsqlConnection conn = new NpgsqlConnection(connstring))
    {
        conn.Open();
        // 检查用户是否存在
        using (NpgsqlCommand cmd = new NpgsqlCommand(@"SELECT COUNT(*) FROM users where username = :username", conn))
        {
            cmd.Parameters.AddWithValue(":username", username);
            int result = Convert.ToInt32(cmd.ExecuteScalar());
            if (result == 0)
            {
                // 插入新用户
                using (NpgsqlCommand insertCmd = new NpgsqlCommand(@"INSERT INTO USERS (username,password) VALUES (:username,:password)", conn))
                {
                    if (password.Length >= 4 && username.Length > 0 && password.Length <= 128 && username.Length <= 128 && !password.Contains(' '))
                    {
                        insertCmd.Parameters.AddWithValue(":username", username);
                        insertCmd.Parameters.AddWithValue(":password", GetMD5(password));
                        insertCmd.ExecuteNonQuery();
                        return "Registration completed successfully#OK";
                    }
                    else
                    {
                        return "Invalid username or password#";
                    }
                }
            }
            else
            {
                return "A user with the same username already exists#";
            }
        }
    }
} 
catch (Exception ex)
{
    return $"Error:{ex.Message} что-то пошло не так#"; 
}

3. 参数命名不一致

插入语句中参数使用username,但SQL里是:username,虽然Npgsql支持自动映射,但统一参数格式避免潜在问题:

insertCmd.Parameters.AddWithValue(":username", username);
insertCmd.Parameters.AddWithValue(":password", GetMD5(password));

4. 客户端Response处理风险

原代码直接Split('#')后访问responseSub[1],如果返回的字符串没有#(比如异常信息格式错误),会导致IndexOutOfRangeException。添加长度判断:

string[] responseSub = response.Split('#');
if (responseSub.Length >= 1)
{
    MessageBox.Show(responseSub[0]);
}

5. WCF异常传递配置(调试用)

默认WCF不会传递详细异常信息到客户端,调试时可修改服务端配置文件,开启异常细节:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

注意生产环境需关闭此配置,避免泄露敏感信息。

额外排查步骤

  • 确认PostgreSQL服务正在运行,端口5432对外开放
  • 验证连接字符串中的用户名、密码、数据库名是否正确
  • 检查数据库表users的结构是否包含username和password字段,且字段类型匹配
  • 在服务端添加日志,记录SQL执行细节和异常信息,便于定位问题

内容的提问来源于stack exchange,提问作者TBO9I_47_XPOMOCOMA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:39:49