VisualStudio "서비스 참조 추가"에서 추가 한 ServiceClient의 바인딩 정보를 app.config 이외에서 검색하고 싶습니다.

12024 단어 VisualStudio
VisualStudio에서 개발하는 프로젝트 내에서 WebService를 사용하는 경우,
"서비스 참조 추가"를 이용하여 서비스에 액세스하기 위한 클라이언트 클래스를 자동 생성하는 것이 편리합니다.

(MSDN) 방법 : 웹 서비스에 대한 참조 추가

그러면 app.config/web.config에 WebService 연결에 대한 설정이 출력되고,
프로그램 실행 시 동적으로 로드되어 서비스 클라이언트를 초기화합니다.

app.config
  <system.serviceModel>
    <bindings>
      <customBinding>        
        <binding name="CustomSoapBinding" openTimeout="00:01:00" receiveTimeout="00:01:00">
          <textMessageEncoding messageVersion="Soap12" />
          <httpTransport maxReceivedMessageSize="4096000" />
        </binding>
      </customBinding>
    </bindings>

    <client>
      <endpoint address="http://hogehoge.net/Service/Endpoint1"
        binding="customBinding" bindingConfiguration="CustomSoapBinding"
        contract="Endpoint1.Endpoint1" name="Service1Port" />
    </client>
  </system.serviceModel>

프로젝트에 "서비스 참조 추가"를 한 상태





1개의 프로젝트로 이용하는 경우는 이것으로 종료입니다만,
여러 프로젝트에서 동일한 WebService에 액세스하는 경우,
DLL에 서비스 클라이언트를 제공하여 각 프로젝트는 해당 DLL을 참조하여 WebService에 액세스하고 싶습니다.

하고 싶은 것은 이런 이미지





이때 문제가 된 것이 이 부분입니다.

app.config/web.config에 WebService 연결에 대한 설정이 출력됩니다.
프로그램 실행 시 동적으로 로드되어 서비스 클라이언트를 초기화합니다.

이런 식으로 만들어야 할 것 같습니다.



DLL을 참조하는 각 프로젝트의 app.config/web.config에 대해
WebService에 연결하기 위한 설정을 제공해야 합니다.


·····아니! !
서비스 클라이언트 DLL을 참조할 때마다 app.config에 설정을 전기해야 하는 것은 매우 귀찮습니다.

내가 요구한 이상형





이것을 실현하는 방법



서비스 참조 추가에서 서비스 클라이언트를 추가한 프로젝트 어셈블리( DLL )와 이름이 같은 구성 파일을 읽는 방법입니다.

ServiceClientFactory.cs
  public static T createServiceClient<T>()
    where T : class 
    {
      Type tt = typeof(T);
      T ret = null;
      // [このメソッドが格納されたアセンブリ].dll.config を読み込む
      var assembly = typeof(ClientFactory).Assembly.GetName().EscapedCodeBase;
      var configPath = System.IO.Path.Combine(new Uri(assembly).LocalPath);

      if (System.IO.File.Exists(configPath))
      {
        // 設定ファイルが見つかったら解析
        var config = System.Configuration.ConfigurationManager.OpenExeConfiguration(configPath);
        var smsg = System.ServiceModel.Configuration.ServiceModelSectionGroup.GetSectionGroup(config);
        ChannelEndpointElement en = null;
        foreach (ChannelEndpointElement e in smsg.Client.Endpoints)
        {
          // ジェネリックで指定されたクラスと同じ Name の Endpoint を検索する
          if (e.Name.Contains(tt.Namespace.Split('.').Last()))
          {
            en = e;
            break;
          }
        }
        // 上の検索で見つかった Endpoint のバインディング設定を取得する
        var elm = smsg.Bindings.CustomBinding.Bindings[en.BindingConfiguration];
        var binding = new System.ServiceModel.Channels.CustomBinding();
        elm.ApplyConfiguration(binding);    // カスタムバインディング定義から、このEndpoint で使用するバインディング情報を割り当てる

        // ここまで読み込んできた Endpoint の設定で、サービスクライアントオブジェクトを初期化します。
        ret = (T)tt.GetConstructor(new Type[] { typeof(System.ServiceModel.Channels.Binding),
                                                typeof(System.ServiceModel.EndpointAddress)})
                                  .Invoke(new object[] { binding,
                                          new System.ServiceModel.EndpointAddress(en.Address) });
      }
      else
      {
        // 設定ファイルが見つからない時は、既定のコンストラクタで初期化する
        // この場合、このメソッドを呼び出しているアセンブリの設定ファイル (app.config /web.config )で
        // サービスクライアントオブジェクトが初期化されます。
        ret = (T)tt.GetConstructor(Type.EmptyTypes).Invoke(null);
      }

    return ret;
  }

메소드를 이용하는 측의 코드



Driver.cs
  void Hogehoge()
  {
    var client = createServiceClient<ServiceClientClassName>();
    .
    .
    .
  }

인수에 패스를 받도록(듯이) 해, 임의의 파일명으로 Binding 의 설정을 보존할 수도 있을까 생각합니다.

좋은 웹페이지 즐겨찾기