Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WCF#-在客户端上优雅地处理服务关闭_Wcf_F#_Fault_Channelfactory - Fatal编程技术网

WCF#-在客户端上优雅地处理服务关闭

WCF#-在客户端上优雅地处理服务关闭,wcf,f#,fault,channelfactory,Wcf,F#,Fault,Channelfactory,我有一些实验代码,基本上只是想让一个简单的场景工作。我有一个客户端将数据流传输到多个服务。我的问题是,如果其中一个服务没有正常关闭,我会得到一个EndpointNotFoundException,我似乎无法处理它。下面是我试图处理这个失败的问题。实际上,我希望从通道列表中删除失败的服务通道,并继续将数据流传输到仍在运行的服务。计时器只是让服务有机会在数据流开始之前启动 let prices = returns a seq of data that is streamed. type Repla

我有一些实验代码,基本上只是想让一个简单的场景工作。我有一个客户端将数据流传输到多个服务。我的问题是,如果其中一个服务没有正常关闭,我会得到一个EndpointNotFoundException,我似乎无法处理它。下面是我试图处理这个失败的问题。实际上,我希望从通道列表中删除失败的服务通道,并继续将数据流传输到仍在运行的服务。计时器只是让服务有机会在数据流开始之前启动

let prices = returns a seq of data that is streamed.

type ReplayDataStream(prices) =
  let evt = new Event<_>()
  member x.Replay() = 
                    async { for line, delay in prices do
                                do! Async.Sleep(delay)
                                evt.Trigger(line) }
                                |> Async.StartImmediate

  member x.PriceChanged = evt.Publish


let main() =
    let addresses = new ResizeArray<EndpointAddress>()

    let announcementService = new AnnouncementService()

    let createChannels addresses =
        let channels = new ResizeArray<IInputDataService>()
        for (address:EndpointAddress) in addresses do
                let channelFactory = new ChannelFactory<IInputDataService>(new BasicHttpBinding(), address)
                let channel = channelFactory.CreateChannel()
                (channel :?> ICommunicationObject).Faulted.Add(fun x -> 
                                                                        (channel :?> ICommunicationObject).Abort()
                                                                        channels.Remove(channel) |> ignore
                                                               )
                channels.Add(channel)
        channels

    let sendMessage(args:ElapsedEventArgs) =
        let channels = createChannels addresses
        for financialDataStream in prices do
        let replayDataStreamA = new ReplayDataStream(financialDataStream)
        for channel in channels do
            try
            //This is where it blows up and the try block isn't catching the exception.
            replayDataStreamA.PriceChanged.Add(channel.InputStringData)
            with
            | :? EndpointNotFoundException as ex -> Console.WriteLine(ex.ToString())
            | :? CommunicationException as ex -> Console.WriteLine(ex.ToString())
            | :? Exception as ex -> Console.WriteLine(ex.ToString())
            replayDataStreamA.Replay()

    let timer = new System.Timers.Timer()
    timer.Enabled <- true
    timer.AutoReset <- false
    timer.Interval <- 30000.0
    timer.Start()
    timer.Elapsed.Add(sendMessage)

    announcementService.OnlineAnnouncementReceived.Add(fun e -> 
                                                                Console.WriteLine(e.EndpointDiscoveryMetadata.Address)
                                                                addresses.Add(e.EndpointDiscoveryMetadata.Address)
                                                                )

    announcementService.OfflineAnnouncementReceived.Add(fun e -> 
                                                                Console.WriteLine(e.EndpointDiscoveryMetadata.Address)
                                                                addresses.Remove(e.EndpointDiscoveryMetadata.Address) |> ignore
                                                                )

    let announcementServiceHost = new ServiceHost(announcementService)
    try
        announcementServiceHost.AddServiceEndpoint(new UdpAnnouncementEndpoint());
        announcementServiceHost.Open();
    with 
    | :? System.ServiceModel.CommunicationException as ex -> Console.WriteLine(ex.ToString())
    | :? System.TimeoutException as ex -> Console.WriteLine(ex.ToString())


    printfn "%s" "Hit any key to close."
    Console.ReadKey() |> ignore
let prices=返回流式传输的数据序列。
类型ReplayDataStream(价格)=
让evt=新事件()
成员x.Replay()=
async{对于行,延迟的价格是多少
do!Async.Sleep(延迟)
evt.触发器(行)}
|>Async.StartImmediate
成员x.PriceChanged=evt.Publish
让main()=
let addresses=new ResizeArray()
let announcementService=new announcementService()
让我们创建通道地址=
let channels=new ResizeArray()
地址do中的(地址:EndpointAddress)for
让channelFactory=新的channelFactory(新的BasicHttpBinding(),地址)
让channel=channelFactory.CreateChannel()
(频道:?>ICommunicationObject)。出现故障。添加(乐趣x->
(通道:?>ICommunicationObject).Abort()
通道。删除(通道)|>忽略
)
频道。添加(频道)
渠道
让发送消息(args:ElapsedEventArgs)=
let channels=createChannels地址
对于财务数据流,价格如何
让replayDataStreamA=新的ReplayDataStream(financialDataStream)
对于通道中的通道,请执行以下操作:
尝试
//这就是它爆炸的地方,try块没有捕获异常。
replayDataStreamA.PriceChanged.Add(channel.InputStringData)
具有
| :? EndpointNotFoundException作为ex->Console.WriteLine(ex.ToString())
| :? 通讯异常为ex->Console.WriteLine(例如ToString())
| :? 异常为ex->Console.WriteLine(ex.ToString())
replayDataStreamA.Replay()
let timer=new System.Timers.timer()
定时器。启用忽略
)
让announcementServiceHost=newservicehost(announcementService)
尝试
announcementServiceHost.AddServiceEndpoint(新的udPanNounceEndpoint());
announcementServiceHost.Open();
具有
| :? System.ServiceModel.CommunicationException as ex->Console.WriteLine(例如ToString())
| :? System.TimeoutException as ex->Console.WriteLine(例如ToString())
printfn“%s”按任意键关闭
Console.ReadKey()|>忽略

Sky Sanders的解释很有道理,应该适用于这种情况。这里有一个

为故障事件提供订阅服务器与在异常处理程序中调用channel.Abort()的操作不完全相同

Add()相当于PriceChanged+=:您正在订阅Price changed事件的处理程序。放置try/with块将捕获订阅时抛出的异常(请考虑事件中的自定义添加/删除实现),而这不是您想要的。您正在寻找一种在调用InputStringData时处理异常的方法。这一思维过程自然会导致失败

在C#生产代码中,在事件端引发异常的点周围放置一个try/catch块。捕获订阅者抛出的异常并进行调试。断言并重试,警告开发人员所有异常都应在订阅者端处理。在代码中,这意味着一个try/with块,它警告并重新抛出evt.Trigger()


您可以公开异步块,而不是在声明时运行它。这将为您提供更高级别的编排能力:在sendMessage中。有一个特殊的API可以捕捉异常,在一个真正值得关注的中心位置处理取消和超时。

在用C语言重写代码后,我终于明白我做错了什么。这就是PriceChanged事件处理程序的外观。我需要捕捉lambda本身内部的异常。现在我需要写一些看起来像生产代码的东西

对于子孙后代,以下是整个方法:

让发送消息(args:ElapsedEventArgs)=
如果(addresses.Count>0),则
地址中的地址怎么办
让channelFactory=新的channelFactory(新的BasicHttpBinding(),地址)
让channel=channelFactory.CreateChannel()
对于财务数据流,价格如何
让replayDataStreamA=新的ReplayDataStream(financialDataStream)
replayDataStreamA.PriceChanged.Add(乐趣x->
尝试
channel.InputStringData x
具有
|:?System.ServiceModel.CommunicationException作为ex->(通道:?>ICommunicationObject).Abort()
)
replayDataStreamA.Replay()

这就是我在上面的代码中尝试实现的解决方案。我怀疑我可能没有正确地将其转换为F#。这基本上就是我在上面的代码中尝试实现的解决方案。也许我把它翻译成F#是不正确的
replayDataStreamA.PriceChanged.Add( fun x -> 
                                                            try
                                                            channel.InputStringData x
                                                            with 
                                                            | :? System.ServiceModel.CommunicationException as ex -> (channel :?> ICommunicationObject).Abort()
                                                            )
let sendMessage(args:ElapsedEventArgs) =
            if(addresses.Count > 0) then
                for address in addresses do
                    let channelFactory = new ChannelFactory<IInputDataService>(new BasicHttpBinding(), address)
                    let channel = channelFactory.CreateChannel()
                    for financialDataStream in prices do
                    let replayDataStreamA = new ReplayDataStream(financialDataStream)
                    replayDataStreamA.PriceChanged.Add( fun x -> 
                                                        try
                                                        channel.InputStringData x
                                                        with 
                                                        | :? System.ServiceModel.CommunicationException as ex -> (channel :?> ICommunicationObject).Abort()
                                                        )
                    replayDataStreamA.Replay()