중욯 : https://blog.naver.com/techshare/220725308257

http://sysnet.pe.kr/220724464263

https://blog.naver.com/techshare/220725308257

http://blog.naver.com/PostView.nhn?blogId=techshare&logNo=220724464263&parentCategoryNo=&categoryNo=1&viewDate=&isShowPopularPosts=true&from=search

이유는 간단합니다. 해당 IService1.GetData 메서드의 코드를 보면,

public string GetData(int value)
{
IService1Callback _callback = OperationContext.Current.GetCallbackChannel<IService1Callback>();
{
Thread.Sleep(value * 1000);

    _callback.Finished(true);
    return string.Format("You entered: {0}", value);
}

}

_callback.Finished 호출이 발생하는 데 그 순간 Socket.Connect("testpc") 호출이 발생하지만 "testpc"에 대한 IP 해석이 되지 않아 Socket Connection timeout이 발생하기까지 대기하게 되고 이 때문에 WCF의 기본 timeout 값에 걸려 "The open operation did not complete within the allotted timeout of 00:00:59.9979992"와 같은 오류 메시지가 발생하는 것입니다.

경험이 없는 WCF 개발자라면, 이 오류 메시지를 보고 WCF timeout 관련 설정을 조정하겠지만 그것으로 해결될 문제가 아닙니다. 더욱 문제는, 이에 대해 WCF를 호스팅하는 IIS 서비스 측에서 이벤트 로그 등을 통한 오류 흔적이 전혀 안 남는다는 점입니다.

이 오류를 쉽게 감지하는 것은 WCF 로깅을 사용하거나 지난 번에 알려드린 procdump를 이용해 보면 됩니다.

try/catch로 조용히 사라진 예외를 파악하고 싶다면?
; http://www.sysnet.pe.kr/2/0/10965

가령, procdump.exe를 이용하는 경우 다음과 같은 오류 메시지가 발생하는 것을 확인할 수 있습니다.

[21:05:05] Exception: E0434F4D.System.Net.WebException ("The remote name could not be resolved: 'testpc'")
[21:05:05] Exception: E0434F4D.System.ServiceModel.EndpointNotFoundException ("There was no endpoint listening at http://testpc/Temporary_Listen_Addresses/1f1be8f1-d610-4797-840c-07ebdbfd3ad1/7e5a35b9-1d00-4a15-9a46-585798e347da that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.")
[21:05:05] Exception: E0434F4D.System.ServiceModel.CommunicationException ("The inactivity timeout of (00:10:00) has been exceeded.")
[21:05:05] Exception: E0434F4D.System.ServiceModel.CommunicationObjectFaultedException ("The communication object, System.ServiceModel.Channels.ServerReliableDuplexSessionChannel, cannot be used for communication because it is in the Faulted state.")

바로 이런 경우처럼, WCF가 자동으로 넘겨주는 "Temporary_Listen_Addresses" 주소를 WCF 서비스 측에서 콜백 호출 시 아무런 문제가 없도록 하는 방법이 ClientBaseAddress를 지정해 주는 것입니다.

이 글의 예에서는 VPN에 알려진 클라이언트 측의 IP 주소를 192.168.10.22라고 가정했을 때 다음과 같이 바인딩 정보를 지정하면 됩니다.

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IService1" clientBaseAddress="http://192.168.10.22/Temporary_Listen_Addresses/">
<security mode="None" />
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://192.168.10.55:8033/Service1.svc" binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IService1" contract="ServiceReference1.IService1" name="WSDualHttpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>

이렇게 바꾸고 WCF 호출을 하면, 서버 측에서는 클라이언트가 새롭게 전달해 준 "http://192.168.10.22/Temporary_Listen_Addresses/.../..." 주소로 역방향 호출을 하게 되고 결과적으로 서비스가 정상적으로 운영이 됩니다.

[출처] C# - WCF wsDualHttpBinding의 ClientBaseAddress 속성|작성자 techshare

<?xml version="1.0" encoding="utf-8"?>

<configuration>

<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 메타데이터 정보를 공개하지 않으려면 배포하기 전에 아래 값을 false로 설정하십시오. -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- 디버깅 목적으로 오류에서 예외 정보를 받으려면 아래의 값을 true로 설정하십시오. 예외 정보를 공개하지 않으려면 배포하기 전에 false로 설정하십시오. -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
<add binding="wsDualHttpBinding" bindingConfiguration="wsDualHttpBindingConfig" scheme="http" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<wsDualHttpBinding>
<binding name="wsDualHttpBindingConfig">
<security mode="None" />
</binding>
</wsDualHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!-- 디버깅 중에 웹 응용 프로그램 루트 디렉터리를 찾으려면 아래 값을 true로 설정하십시오. 웹 응용 프로그램 폴더 정보를 공개하지 않으려면 배포 전에 false로 설정하십시오. -->
<directoryBrowse enabled="true"/>
</system.webServer>

</configuration>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService1
{
// 참고: "리팩터링" 메뉴에서 "이름 바꾸기" 명령을 사용하여 코드, svc 및 config 파일에서 클래스 이름 "Service1"을 변경할 수 있습니다.
// 참고: 이 서비스를 테스트하기 위해 WCF 테스트 클라이언트를 시작하려면 솔루션 탐색기에서Service1.svc나 Service1.svc.cs를 선택하고 디버깅을 시작하십시오.
public class Service1 : IService1
{
static IService1Callback callback = null;
static IService1Callback callback2 = null;

    public string GetData(int value)
    {
        if(callback == null && value == 1)
            callback = OperationContext.Current.GetCallbackChannel<IService1Callback>();

        if (callback2 == null && value == 2)
            callback2 = OperationContext.Current.GetCallbackChannel<IService1Callback>();

        System.Threading.Thread.Sleep(value * 100);

        if (callback != null)
            callback.Finished(true);
        if (callback2 != null)
            callback2.Finished(true);
        /*

callback.Finished(true); // 이 메서드를 호출한 클라이언트 측의 Finished 메서드를 호출
[출처] C# - wsDualHttpBinding WCF 예제 프로그램|작성자 techshare
*/
return string.Format("You entered: {0}", value);
}

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite == null)
        {
            throw new ArgumentNullException("composite");
        }
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }
}

}