c# - 如何关闭用于在 WCF 服务中生成流式处理结果的数据库连接?

标签 c# wcf streaming database-connection

我找不到任何关于在 WCF 服务操作中正确关闭数据库连接的文档。我有一个通过以下方法返回流式响应的服务。

public virtual Message GetData()
{
    string sqlString = BuildSqlString();
    SqlConnection conn = Utils.GetConnection();
    SqlCommand cmd = new SqlCommand(sqlString, conn);
    XmlReader xr = cmd.ExecuteXmlReader();

    Message msg = Message.CreateMessage(
        OperationContext.Current.IncomingMessageVersion,
        GetResponseAction(),
        xr);

    return msg;
}

我无法在方法内关闭连接,否则响应消息的流将终止。由于在该方法完成后控制返回到 WCF 系统,我不知道之后如何关闭该连接。如有任何建议或对其他文档的指示,我们将不胜感激。

最佳答案

实际上,这是个好问题。不幸的是,我认为没有好的答案。实际上有一个活跃的 Microsoft Connect关于这个问题的票。

通常,如果您想要流式传输结果并且您只需要一个常规的SqlDataReader,您可以使用ExecuteReader采用 CommandBehavior 的重载,特别是 CommandBehavior.CloseConnection。如果阅读器是使用此命令行为创建的,那么当您关闭(或Dispose)阅读器时,它也会关闭底层连接,因此您永远不必担心处理SqlConnection

不幸的是,ExecuteXmlReader 没有等效的重载。您必须显式处理 SqlConnection

解决此问题的一种方法是实现您自己的 XmlReader 后代,包装从 ExecuteXmlReader 获得的真正的 XmlReader 并强制关闭连接关闭。

基本思想是从 XmlReader 派生并包装真正的 XmlReaderSqlConnection 本身。像这样:

class SqlXmlReader : XmlReader
{
    private SqlConnection connection;
    private XmlReader reader;

    public SqlXmlReader(SqlCommand cmd)
    {
        if (cmd == null)
            throw new ArgumentNullException("cmd");
        this.connection = cmd.Connection;
        this.reader = cmd.ExecuteXmlReader();
    }

    public override void Close()
    {
        reader.Close();
        connection.Close();
    }
}

这会直接从 SqlCommand 获取连接和读取器,因此不会出现连接/读取器不匹配的情况。您还需要实现其余的 XmlReader 方法和属性 - 这只是很多无聊的方法代理:

    public override int AttributeCount
    {
        get { return reader.AttributeCount; }
    }

    public override string BaseURI
    {
        get { return reader.BaseURI; }
    }

    public override int Depth
    {
        get { return reader.Depth; }
    }

    public override bool EOF
    {
        get { return reader.EOF; }
    }

    public override string GetAttribute(int i)
    {
        return reader.GetAttribute(i);
    }

    public override string GetAttribute(string name, string namespaceURI)
    {
        return reader.GetAttribute(name, namespaceURI);
    }

    public override string GetAttribute(string name)
    {
        return reader.GetAttribute(name);
    }

    public override bool HasValue
    {
        get { return reader.HasValue; }
    }

    public override bool IsEmptyElement
    {
        get { return reader.IsEmptyElement; }
    }

    public override string LocalName
    {
        get { return reader.LocalName; }
    }

    public override string LookupNamespace(string prefix)
    {
        return reader.LookupNamespace(prefix);
    }

    public override bool MoveToAttribute(string name, string ns)
    {
        return reader.MoveToAttribute(name, ns);
    }

    public override bool MoveToAttribute(string name)
    {
        return reader.MoveToAttribute(name);
    }

    public override bool MoveToElement()
    {
        return reader.MoveToElement();
    }

    public override bool MoveToFirstAttribute()
    {
        return reader.MoveToFirstAttribute();
    }

    public override bool MoveToNextAttribute()
    {
        return reader.MoveToNextAttribute();
    }

    public override XmlNameTable NameTable
    {
        get { return reader.NameTable; }
    }

    public override string NamespaceURI
    {
        get { return reader.NamespaceURI; }
    }

    public override XmlNodeType NodeType
    {
        get { return reader.NodeType; }
    }

    public override string Prefix
    {
        get { return reader.Prefix; }
    }

    public override bool Read()
    {
        return reader.Read();
    }

    public override bool ReadAttributeValue()
    {
        return reader.ReadAttributeValue();
    }

    public override ReadState ReadState
    {
        get { return reader.ReadState; }
    }

    public override void ResolveEntity()
    {
        reader.ResolveEntity();
    }

    public override string Value
    {
        get { return reader.Value; }
    }

沉闷,沉闷,沉闷,但它有效。此读取器将在完成后为您关闭连接,与使用 CommandBehavior.CloseConnection 打开的 SqlDataReader 相同。

最后要做的是创建一个扩展方法,使其更易于使用:

public static class SqlExtensions
{
    public static XmlReader ExecuteSafeXmlReader(this SqlCommand cmd)
    {
        return new SqlXmlReader(cmd);
    }
}

一旦你有了这个,而不是写:

XmlReader xr = cmd.ExecuteXmlReader();

你写:

XmlReader xr = cmd.ExecuteSafeXmlReader();

就是这样。现在,当 WCF 关闭您的阅读器时,它会自动关闭底层连接。

(免责声明:这还没有经过正式测试,但我看不出它为什么不起作用,除非 WCF 实际上没有关闭读取器。一定要针对实时 SQL 连接实际测试它以确保它真的不会泄漏连接。)

关于c# - 如何关闭用于在 WCF 服务中生成流式处理结果的数据库连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2596910/

相关文章:

javascript - fancybox href ="imageURL"使用 datalist1 中填充的 image1

c# - 可空属性的映射结果为 0 但不是 Null

c# - 测试 WCF URL 的可用性

c# - 异步调用 wcf 4.5 WCF 服务

webrtc - 如何将网页从服务器端直播到 YouTube 和 Facebook,并为该流提供 WebRTC 输出?

http - 如何使用 wreq 只下载部分响应?

c# - 如何使用 RX 限制事件流?

c# - 如何从 NHibernate 调用没有结果的存储过程?

wcf - 更新开发者许可证后出现错误。无法连接到 WCF 服务

javascript - Node.js:从 MongoDB 流式传输到文件