【问题标题】:WCF Callback implementation: Service is consistently returning a null operation contextWCF 回调实现:服务始终返回空操作上下文
【发布时间】:2009-11-09 15:20:41
【问题描述】:

我目前正在尝试通过在 WCF 中实现回调来显示在服务器上运行的 SSIS 包的进度。这在一定程度上起作用;基本上 OperationContext.Current 在一些侦听器事件已经发生后返回 null (在初始 SSIS 包执行调用后大约 30 秒)。这是我正在使用的一些代码:

WCF 服务方法:

var dts = new Microsoft.SqlServer.Dts.Runtime.Application();

PackageEventListener listener = new PackageEventListener();
listener.OnPackageProgress += new PackageEventListener.PackageProgressChangedHandler(listener_OnPackageProgress);
...
if (package.Execute(null, null, listener, null, null) == DTSExecResult.Failure)
...

private static void listener_OnPackageProgress(object package, EventArgs packageinfo)
{
    var context = System.ServiceModel.OperationContext.Current;
    if (context == null) return;

    IXLoadMarriageCallback callback = context.GetCallbackChannel<IXLoadMarriageCallback>();
    if (callback != null)
    {
        PackageProgressEventArgs eventArgs = (PackageProgressEventArgs)packageinfo;
        callback.OnProgressCallback(eventArgs.ProgressDescription);
    }
}

public interface IXLoadMarriageCallback
{
    [OperationContract(IsOneWay = true)]
    void OnProgressCallback(string message);
}

(PackageEventListener是一个继承自Microsoft.SqlServer.Dts.Runtime.DefaultEvents的类)

服务标记如下:

[ServiceBehavior(
    InstanceContextMode = InstanceContextMode.PerSession,
    ConcurrencyMode = ConcurrencyMode.Reentrant
)]
public class IntegrationServicesService : IIntegrationServicesService

并且服务接口标记如下:

[ServiceContract(
    CallbackContract = typeof(Business.IXLoadMarriageCallback),
    SessionMode = SessionMode.Required
)]
public interface IIntegrationServicesService

我使用的是 net tcp 绑定,服务端配置如下:

<bindings>
    <netTcpBinding>
        <binding name="LongReliableTCPBinding"
            closeTimeout="10:01:00" openTimeout="10:01:01" receiveTimeout="08:00:01" sendTimeout="08:00:02"
            transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
            hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="4194304" maxBufferSize="4194304" maxConnections="10" maxReceivedMessageSize="4194304">
            <readerQuotas maxDepth="32" maxStringContentLength="4194304" maxArrayLength="4194304" maxBytesPerRead="4194304" maxNameTableCharCount="4194304" />
            <reliableSession ordered="true" inactivityTimeout="08:00:03" enabled="true" />
            <security mode="Transport">
                <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                <message clientCredentialType="Windows" />
            </security>
        </binding>
    </netTcpBinding>
</bindings>

我看不到任何异常被抛出。为相当不完整的代码示例道歉,因为有很多事情发生(只是为了获得进展的迹象!)。

根据要求,这里是一些调用服务方法的客户端代码(它是一个演示者):

public class XLoadPresenter : IIntegrationServicesServiceCallback, IDisposable
{
    private IXLoadView view;
    private readonly IIntegrationServicesServiceClient integrationServicesServiceClient;
    private readonly IXLoadServiceClient xloadServiceClient;

    public XLoadPresenter(IXLoadServiceClient xloadServiceClient)
    {
        var context = new System.ServiceModel.InstanceContext(this);
        this.integrationServicesServiceClient = new IntegrationServicesServiceClient(context);

        this.xloadServiceClient = xloadServiceClient;
    }

    ...

    private void InvokeXLoadMarriages()
    {
        integrationServicesServiceClient.BeginXLoadMarriage(view.Database, OnEndXLoadMarriages, null);
    }
    ...
}

【问题讨论】:

  • 你能提供一个代理检索代码的片段吗?你确定通过InstanceContext传递非空回调实例吗?

标签: c# wcf ssis


【解决方案1】:

已经弄清楚发生了什么。问题在于我对 DefaultEvents 类的实现:

public class PackageEventListener : DefaultEvents
{
    public PackageProgressChangedHandler OnPackageProgress;
    public PackagePostExecuteHandler OnPackagePostExecute;

    public delegate void PackageProgressChangedHandler(object package, EventArgs packageInfo);
    public delegate void PackagePostExecuteHandler(object package, EventArgs packageInfo);

    public override void OnProgress(TaskHost taskHost, string progressDescription, int percentComplete, int progressCountLow, int progressCountHigh, string subComponent, ref bool fireAgain)
    {
        OnPackageProgress(this, new PackageProgressEventArgs(taskHost, progressDescription, subComponent));

        base.OnProgress(taskHost, progressDescription, percentComplete, progressCountLow, progressCountHigh, subComponent, ref fireAgain);
    }

    public override void OnPostExecute(Executable exec, ref bool fireAgain)
    {
        OnPackagePostExecute(this, new PackagePostExecuteEventArgs(exec));

        base.OnPostExecute(exec, ref fireAgain);
    }
}

我正在覆盖 OnPostExecute 但没有附加处理程序,即在我遇到的问题中列出的代码示例中:

listener.OnPackageProgress += new PackageEventListener.PackageProgressChangedHandler(listener_OnPackageProgress);

但没有:

listener.OnPackagePostExecute += PackageEventListener.PackagePostExecuteHandler(listener_OnPackagePostExecute);

因此,被覆盖的 OnPostExecute 引发了一个“隐藏的”空引用异常(在某种意义上,没有报告异常并且 OperationContext.Current 被设置为空)。

我已经通过简单地默认一个空委托来修复它,即:

public PackageProgressChangedHandler OnPackageProgress = delegate { };
public PackagePostExecuteHandler OnPackagePostExecute = delegate { };

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多