2013-03-14 2 views
4

어떻게 시작했는지 잘 모르겠다는 문제점이 있습니다. 이전에 제대로 작동했음을 확신하지만 변경 사항을 기억하지는 않습니다.WCF 클라이언트 서비스 참조에서 사용자 지정 끝점 동작을 사용하지 않습니다.

먼저 작동하지 않는 이유에 직접적인 영향을주지 않는 한 먼저 설정에 집중하지 마십시오. 나는 그것이 작동하지 않게 만드는 원인만큼 비평을 찾고 있지 않습니다.

HTTP 헤더 인증을 사용하는 API를 노출합니다. 내 솔루션에서이 API의 작업을 소비하고 있습니다. 상용구 코드를 피하기 위해, 나는 CustomClientMessageInspector 및 메시지에 헤더를 추가하기위한 책임이있는 CustomCredentialBehavior를 사용하여 내가 서비스를 초기화하려는 ClientFactory을 만들었습니다.

아이디어는 내가 서비스를 이용해야하는 경우, 코드는 다음과 유사 할 것입니다 :

IClientCredentials credentials = ClientCredentials.FromToken(); 
var service = ClientFactory.CreateClientInstance<API.Clients.ClientServiceClient>(credentials); 

ClientFactory의 모습을 다음 (이 너무 많이 판단하지 마십시오).

public class ClientFactory 
{ 
    public static T CreateClientInstance<T>(IClientCredentials clientCredentials) 
    { 

     T t = Activator.CreateInstance<T>(); 
     var factory = t.GetType().GetProperty("ChannelFactory"); 
     using (var scope = new OperationContextScope((IContextChannel) t.GetType().GetProperty("InnerChannel").GetValue(t,null))) 
     { 

      var endpointBehavior = new CustomCredentialBehavior(clientCredentials); 
      if (((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.Any(p => p.GetType() == typeof(CustomCredentialBehavior))) 
      { 
       var behavior = 
        ((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.FirstOrDefault(
         p => p.GetType() == typeof (CustomCredentialBehavior)); 
       ((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.Remove(behavior); 
      } 

      ((ChannelFactory)factory.GetValue((t),null)).Endpoint.Behaviors.Add(endpointBehavior); 

      return t; 
     } 
    } 
} 

CustomEndpointBehavior :

public class CustomCredentialBehavior:IEndpointBehavior 
{ 
    private IClientCredentials _clientCredentials { get; set; } 

    public CustomCredentialBehavior(IClientCredentials clientCredentials) 
    { 
     _clientCredentials = clientCredentials; 
    } 



    public void Validate(ServiceEndpoint endpoint) 
    { 

    } 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 

    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 

    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
      clientRuntime.MessageInspectors.Add(new ClientCredentialMessageInspector(_clientCredentials)); 
    } 
} 

ClientMessageInspector :

내가 직면하고 문제는 내가 볼 수 있지만 서비스가 올바른 엔드 포인트 동작으로 ClientFactory에서 반환 된 것입니다
public class ClientCredentialMessageInspector:IClientMessageInspector 
{ 
    private IClientCredentials _clientCredentials; 

    public ClientCredentialMessageInspector(IClientCredentials clientCredentials) 
    { 
     _clientCredentials = clientCredentials; 
    } 

    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
      var buffer = request.CreateBufferedCopy(Int32.MaxValue); 
      request = buffer.CreateMessage(); 

      HttpRequestMessageProperty messageProperty = 
       (HttpRequestMessageProperty) request.Properties["httpRequest"]; 
      messageProperty.Headers.Add("AccessKey", _clientCredentials.AccessKey.ToString()); 
      messageProperty.Headers.Add("ClientKey", _clientCredentials.ClientKey.ToString()); 
      messageProperty.Headers.Add("AuthorizationKey", _clientCredentials.AuthorizationKey); 
     return null; 
    } 

    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 

    } 
} 

, ApplyClientBehavior()는 호출되지 않습니다. 어떤 이유로 WCF 파이프 라인을 원래대로 사용하지 않는 것 같습니다.

내가 추가 한 EndpointBehavior가 사용되도록 ClientFactory에서 인스턴스를 만들려면 어떻게해야합니까?

EDIT 내가보고있는 것을 보여주기 위해 서비스 작업이 호출되기 바로 전에 조사 식 창 스크린 샷이 있습니다. 내 CustomCredentialBehavior가 모든 올바른 값으로 초기화되었음을 보여줍니다.

enter image description here

편집 나는 카를로스 '충고를 따랐다 (의견의)와 전화를 단순화하고, 대신 작동하는 다음 호출을 사용했다. 그러나 문제는 원래 코드에서 어디에 있는지 파악하여 서비스 참조를 사용해야 할 때마다 상용구 코드를 호출 할 필요가 없습니다.

 API.Clients.Client client = new API.Clients.Client(); 
     client.Active = true; 
     client.Enabled = true; 
     client.Name = model.ClientName; 

     API.Clients.ClientServiceClient service = new ClientServiceClient(); 
     service.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentialBehavior(ClientCredentials.FromToken())); 
     var response = service.CreateClient(new CreateClientRequest() { Client = client }); 

어떤 생각을 왜 초기 코드가 작동하지 않습니다,이 일을 수행합니다

다음 코드는 작동?

+1

이 코드에는 간접 참조가 많이 있습니다. 간단한 방법 (예 : 공장, 제네릭, 리플렉션 등이없는)을 사용하여 작업을 시작하는 시점을 간단하게하려고 할 수 있습니다. 그 시점에서 추상화로 되돌아 가며 어디서 깨지는 지 살펴보십시오. 그것은 문제를 지적 할 것입니다. – carlosfigueira

+0

나는 그것을 시험해 볼 것이다. 또한, 최근에 .NET 4.5에서 4.0으로 저하되는 것과 관련이있을 수 있습니까? 컴파일하기 위해 확장 성 구현을 몇 가지 수정해야했습니다. 주로 종점 동작 – TheJediCowboy

+0

@carlosfigueira를 사용하여 조언을 구한 후 위의 편집에 표시된보다 구체적인 버전으로 단순화 한 것입니다. 이제 첫 번째 버전의 문제점을 파악하려고합니다. 머리 꼭대기에서 아무것도 보이지 않습니까? – TheJediCowboy

답변

3

내가 여기 뭔가를 놓칠 수도 있지만, 왜 그렇게 복잡한 경로를 택할 것인지는 잘 모르겠다.당신은 인터페이스 (안 클라이언트 클래스) 계약을 체결 한 경우

, 바로 다음을 수행하십시오

var factory = new ChannelFactory<T>(); //T is the interface of the service 

factory.Endpoint.Behaviors.Add()이 동작을 추가하는 방법을 제공합니다. 그리고 실제 서비스를 만들려면 factory.CreateChannel()을 호출하면 T이 반환됩니다. 요약 그래서

:

public T Create<T>() 
{ 
    var factory = new ChannelFactory<T>(); 
    factory.Endpoint.Behaviors.Add(<here goes your behavior>); 
    return factory.CreateChannel(); 
} 

는 또한 그에 따라 클라이언트 채널 폐기해야합니다. IoC를 사용하는 경우 컨테이너에서 처리 할 수 ​​있습니다 (예 : Autofac).