【问题标题】:Wcf code works in console and WinForms app (small test apps), but not in our system WinForms applicationWcf 代码在控制台和 WinForms 应用程序(小型测试应用程序)中有效,但在我们的系统 WinForms 应用程序中无效
【发布时间】:2021-09-12 16:54:36
【问题描述】:

首先,我对 WCF 还很陌生,所以在回复时请记住这一点。

问题是我创建了一个在客户端和服务器之间共享的 WCF 库 (AppCommWcf)。当我使用 AppCommWcf 库编写控制台应用程序并调用它时,它工作正常。当我对测试 WinForms 应用程序执行相同操作时,它工作正常,但是,当我在我们的 WinForms 系统应用程序中使用它时,客户端无法连接到服务器。客户端和服务器都在我的本地机器上运行。我没有在它们各自的 application.exe.config 文件中使用任何值。在你去使用下面的代码尝试和重现之前,正如我之前所说,这在较小的应用程序中运行良好,但不是我们超过一百万行代码的应用程序,所以我希望经验丰富的 WCF 专业人士可以告诉我一些事情至于为什么客户失败了。但我所做的只是在下面 3 个不同的应用程序之间使用相同的确切代码,它只会在我们的系统应用程序中失败。

我运行的测试:

  • 系统应用服务器正在运行,系统应用客户端正在运行,客户端无法连接到服务器。
  • 控制台作为服务器运行,System app服务器运行(WCF代码注释掉),System App客户端运行,客户端通过WCF连接控制台服务器,完成方法调用。
  • 控制台作为客户端运行,System App 服务器正在运行,客户端无法连接到服务器。

根据上面的测试,服务器似乎有问题,但我无法弄清楚为什么它只在系统应用程序服务器中失败,但在控制台和 WinForms 服务器测试应用程序中使用相同的客户端/服务器代码全部。

这是来自 AppCommWcf 库的代码:

Project References:
System
System.Runtime.Serialization
System.ServiceModel

CameraCtrlCommClient.cs:

using System.ServiceModel;

namespace AppCommWcf
{
    public partial class CameraCtrlCommClient : ClientBase<ICameraCtrlComm>, ICameraCtrlComm
    {
        public CameraCtrlCommClient(string bindUrl) : base(new WSHttpBinding(), new EndpointAddress(bindUrl)) { }

        public LockRequestResponse RequestLock(LockTypeWcf lckType, string camName, int stationId, string userName, bool takeCtrlIfLocked)
        {
            return base.Channel.RequestLock(lckType, camName, stationId, userName, takeCtrlIfLocked);
        }
    }
}

CameraCtrlCommServer.cs:

using System;
using System.ServiceModel;

namespace AppCommWcf
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class CameraCtrlCommServer : ICameraCtrlComm
    {
        public delegate LockRequestResponse LockEventHandler(LockTypeWcf lckType, string camName, int stationId, string userName, bool takeCtrlIfLocked);

        public event LockEventHandler LockRequested;
        static ServiceHost m_svcHost;

        CameraCtrlCommServer() { }

        public string BindingUrl { get; private set; }

        public void Close()
        {
            if (m_svcHost != null)
            {
                m_svcHost.Close();
                m_svcHost = null;
            }
        }

        public LockRequestResponse RequestLock(LockTypeWcf lckType, string camName, int stationId, string userName, bool takeCtrlIfLocked)
        {
            return LockRequested.Invoke(lckType, camName, stationId, userName, takeCtrlIfLocked);
        }

        public static CameraCtrlCommServer StartServiceHost(string bindUrl)
        {
            CameraCtrlCommServer result = null;

            if (m_svcHost == null)
            {
                result = new CameraCtrlCommServer { BindingUrl = bindUrl };
                m_svcHost = new ServiceHost(result, new Uri(bindUrl))
                {
                    OpenTimeout = new TimeSpan(0, 0, 30),
                    CloseTimeout = new TimeSpan(0, 0, 10)
                };

                m_svcHost.AddServiceEndpoint(typeof(ICameraCtrlComm), new WSHttpBinding(), bindUrl);
                m_svcHost.Faulted += OnSvcHostFaulted;
                m_svcHost.Opened += OnSvcHostOpened;
                m_svcHost.Closing += OnSvcHostClosing;
                m_svcHost.Closed += OnSvcHostClosed;
                m_svcHost.UnknownMessageReceived += OnSvcHostUnknownMsgRecvd;

                m_svcHost.Open();
            }
            else
            {
                throw new Exception("The service host has already been started.");
            }

            return result;
        }

        static void OnSvcHostUnknownMsgRecvd(object sender, UnknownMessageReceivedEventArgs e)
        {
        }

        static void OnSvcHostClosed(object sender, EventArgs e)
        {
        }

        static void OnSvcHostClosing(object sender, EventArgs e)
        {
        }

        static void OnSvcHostOpened(object sender, EventArgs e)
        {
        }

        static void OnSvcHostFaulted(object sender, EventArgs e)
        {
        }
    }
}

枚举.cs:

using System.Runtime.Serialization;

namespace AppCommWcf
{
    /// <summary>
    /// The type of lock being requested.  These values must match BMS.ElectroOptic.C4IAppOffEnum.BMSSensorLockTypeEnum
    /// </summary>
    [DataContract(Name = "LockTypeWcf", Namespace = "http://schemas.datacontract.org/2004/07/AppCommWcf")]
    public enum LockTypeWcf : int
    {
        /// <summary>
        /// The camera is not locked.
        /// </summary>
        [EnumMember]
        NotLocked = 0,
        /// <summary>
        /// A manual lock was performed by clicking the Lock toolbar button on a video, cannot be overridden except by another
        /// user or an <see cref="Entity"/> lock.
        /// </summary>
        [EnumMember]
        Manual,
        /// <summary>
        /// An action was performed that required an auto-lock and an auto-unlock if not other action is taken within
        /// the time specified in C4IAppSimple.BMSSEOMngrParamsOfRoot.AutoUnlockTimeout.  Can be overridden by another user
        /// or <see cref="Manual"/> or <see cref="Entity"/>.
        /// </summary>
        [EnumMember]
        Auto,
        /// <summary>
        /// A lock was performed by an entity action, i.e. House Call, Line Scan or Investigation.  Can be overridden by
        /// another user or <see cref="Manual"/> or <see cref="Auto"/>.
        /// </summary>
        [EnumMember]
        Entity
    }

    #region LockPromptResponse enum
    /// <summary>
    /// The possible responses from <see cref="BMSEOMngr.RequestCameraLock(BMSSensorLockTypeEnum, BMSEOChannelEnt, int, string)"/>
    /// or <see cref="BMSEOMngr.RequestCameraLock(BMSSensorLockTypeEnum, InfSensorId, int, string)"/>.
    /// </summary>
    [DataContract(Name = "LockRequestResponse", Namespace = "http://schemas.datacontract.org/2004/07/AppCommWcf")]
    public enum LockRequestResponse
    {
        /// <summary>
        /// The video is not locked.
        /// </summary>
        [EnumMember]
        NotLocked = 0,
        /// <summary>
        /// The video is locked by the current user.
        /// </summary>
        [EnumMember]
        LockedByCurrentUser,
        /// <summary>
        /// The video is locked by a different user.
        /// </summary>
        [EnumMember]
        LockedByOtherUser
    }
    #endregion

}

ICameraCtrlComm.cs:

using System.ServiceModel;

namespace AppCommWcf
{
    [ServiceContract]
    public interface ICameraCtrlComm
    {
        [OperationContract(Action = "http://tempuri.org/ICameraLockComm/RequestLock", ReplyAction = "http://tempuri.org/ICameraLockComm/RequestLockResponse")]
        LockRequestResponse RequestLock(LockTypeWcf lckType, string camName, int stationId, string userName, bool takeCtrlIfLocked);
    }
}

服务器调用代码

using AppCommWcf;

CameraCtrlCommServer m_camCtrlServer;
Main()
{
    m_camCtrlServer = CameraCtrlCommServer.StartServiceHost(bindUrl);
    m_camCtrlServer.LockRequested += OnServerLockRequested;
}

LockRequestResponse OnServerLockRequested(LockTypeWcf lckType, string camName, int stationId, string userName, bool takeCtrlIfLocked)
{
    return LockRequestResponse.LockedByCurrentUser;
}

客户端调用代码:

using AppCommWcf;
using System.ServiceModel.Channels;

CameraCtrlCommClient m_camCtrlClient;

void Main()
{
    TimeSpan timeout = new TimeSpan(0, 0, 15); //So I don't have to wait a minute to find out it failed to connect.

    m_camCtrlClient = new CameraCtrlCommClient(bindUrl);
    Binding binding = m_camCtrlClient.Endpoint.Binding;

    binding.OpenTimeout = timeout;
    binding.ReceiveTimeout = timeout;
    binding.SendTimeout = timeout;

}

这是 WCF 日志的屏幕截图,希望对您有所帮助,如果您需要给定行的详细信息,请告诉我,我会将其发布在 cmets 中,因为这里没有足够的空间来发布整个日志. 服务器日志: 客户日志: 异常文本是: 对“http://localhost:10821/CameraCtrlComm”的 HTTP 请求已超过分配的超时 00:00:14.9990000。分配给此操作的时间可能是较长超时的一部分。

【问题讨论】:

  • 事件日志中是否记录了任何异常或错误?随机猜测:您是从网络驱动器还是映射的网络驱动器运行 WinForms 应用程序?
  • 事件日志中没有任何内容,将其清除,重新运行应用程序,刷新视图,为空。不,一切都在我的本地计算机上运行,​​没有网络连接用于 WCF 功能。我使用“h_ttp://localhost:10821/CameraCtrlComm 作为绑定 url,在此评论中有意添加下划线以便显示。

标签: c# wcf


【解决方案1】:

问题最终是我在非 Windows 消息循环线程上实例化 ServiceHost。一旦我创建了自己的线程并使用 Application.Run 让它在该线程中等待,直到应用程序退出,它就可以工作了。我希望这对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    相关资源
    最近更新 更多