2016-06-10 2 views
4

클라이언트에 이벤트를 발생 시키려면 WCF 서비스가 필요합니다. 그 콜백 채널을 통해 발생 읽었습니다, 나는 다음과 같은 방식으로 그것을 구현했습니다 : 서비스 인터페이스 :ChannelFactory를 통해 생성 된 WCF 서비스에서 콜백 채널을 설정하는 방법은 무엇입니까?

public interface IServiceCallback 
{ 
    [OperationContract(IsOneWay = true)] 
    void OnNewAlert(Alert a); 
    [OperationContract(IsOneWay = true)] 
    void OnProductEdited(Product p); 
    [OperationContract(IsOneWay = true)] 
    void OnHighlightChanged(Dictionary<User, List<Product>> highlighted); 
    [OperationContract(IsOneWay = true)] 
    void OnCatalogUpdated(); 


    event EventHandler NewAlert; 
    event EventHandler ProductEdited; 
    event EventHandler HighlightChanged; 
    event EventHandler CatalogUpdated; 
} 
[ServiceContract(CallbackContract = typeof(IServiceCallback))] 
public interface IService : IDisposable 
{ 
    [OperationContract] 
    List<Product> GetProducts(Predicate<Product> match = null, int limit = 0, string username = null); 
    [OperationContract] 
    Product GetProduct(Predicate<Product> match, string username = null); 
    [OperationContract] 
    Product GetRandomProduct(Predicate<Product> match = null, string username = null); 
    [OperationContract] 
    int GetFlagIndex(string flagName); 
    [OperationContract] 
    void SetFlag(string pid, string flagName, bool value); 
    [OperationContract] 
    List<Alert> GetAlerts(string username); 
    [OperationContract] 
    void DismissAlert(Alert alert, String username); 
    [OperationContract] 
    void HighlightProduct(List<string> pids, string user); 
    [OperationContract] 
    void EditProduct(string pid, Dictionary<string, object> fieldValues, string username = null); 
    [OperationContract] 
    void AttachModule(IModule m); 
    [OperationContract] 
    void Ping(); 

    event EventHandler NewAlert; 
    event EventHandler ProductEdited; 
    event EventHandler HighlightChanged; 
    event EventHandler CatalogUpdated; 
} 

서비스 구현 : 클라이언트에

namespace Service 
{ 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Reentrant)] 
public class ServiceInstance : IService 
{ 
    List<IServiceCallback> callbackChannels = new List<IServiceCallback>(); 
    //other vars 

    public ServiceInstance() 
    { 
      //lots of stuff here 
    } 

    private User SignalUser(string username) 
    { 
     if (username == null) 
      return null; 

     IServiceCallback channel = OperationContext.Current.GetCallbackChannel<IServiceCallback>(); 
     if (!callbackChannels.Contains(channel)) //if CallbackChannels not contain current one. 
     { 
      callbackChannels.Add(channel); 
     } 

     User user = knownUsers.Find(p => p.username == username); 
     if (user == null) 
     { 
      user = new User(); 
      user.username = username; 
      user.highlighColor = Color.FromArgb(r.Next(0, 128), r.Next(0, 128), r.Next(0, 128)); 
      knownUsers.Add(user); 
      foreach (KeyValuePair<Alert, List<User>> kvp in alerts) 
      { 
       kvp.Value.Add(user); 
      } 
     } 
     user.lastOnline = DateTime.Now; 
     if(!onlineUsers.Contains(user)) 
      onlineUsers.Add(user); 

     return user; 
    } 

    //lots of other things here 
} 
} 

콜백 구현 :

class ServiceEventHandler : IServiceCallback 
{ 
    public event EventHandler NewAlert; 
    public event EventHandler ProductEdited; 
    public event EventHandler HighlightChanged; 
    public event EventHandler CatalogUpdated; 

    public void OnCatalogUpdated() 
    { 
     CatalogUpdated?.BeginInvoke(null, null, null, null); 
    } 

    public void OnHighlightChanged(Dictionary<User, List<Product>> highlighted) 
    { 
     HighlightChanged?.BeginInvoke(highlighted, EventArgs.Empty, null, null); 
    } 

    public void OnNewAlert(Alert a) 
    { 
     NewAlert?.BeginInvoke(a, EventArgs.Empty, null, null); 
    } 

    public void OnProductEdited(Product p) 
    { 
     ProductEdited?.BeginInvoke(p, EventArgs.Empty, null, null); 
    } 
} 

여기 내 문제가 있습니다. 클라이언트 쪽에서는 이 StackOverflow의 응답에 따라

EventHandler eventHandler = new EventHandler(); 
MyServiceClient client = new MyServiceClient(new InstanceContext(eventHandler)); 

:이 같은 서비스에 전달하기로 https://stackoverflow.com/a/1143777/2018696

하지만 내 클라이언트 구현에 대해 알고하지 않기 때문에 나는이 같은 내 서비스에 연결하지 마십시오 서비스의, 그것은 단지 2 개의 공용 영역을 알고있다! 그래서 나는 다음과 같이 연결합니다

public static IService GetService(string serviceAddress) 
    { 
     Uri service_uri = new Uri(serviceAddress); 
     var endpoint = new EndpointAddress(service_uri, new[] { AddressHeader.CreateAddressHeader(settings["username"], "", "") }); 
     IService service = ChannelFactory<IService>.CreateChannel(new BasicHttpBinding(), endpoint); 
     return service; 
    } 

그래서 어떻게 콜백이 작동하려면 어떻게해야합니까?

업데이트 : 코멘트에 의해 제안 된대로, 내가 WsDualHTTPBinding와 DuplexChannelFactory과은 BasicHttpBinding으로 ChannelFactory에 교체, 그리고 서버에서 응답을받지 않도록,

좋아. 콜백 처리기를 긁으면 BasicHTTPBinding 응답을 얻습니다. 그래서 본질적 :

[ServiceContract] 
BasicHttpBinding(); 
ChannelFactory<IService>.CreateChannel(binding, endpoint); 

이 ^이

[ServiceContract(CallbackContract = typeof(IServiceCallback))] 
WSDualHttpBinding(WSDualHttpSecurityMode.None); 
DuplexChannelFactory<IService>.CreateChannel(new InstanceContext(handler), binding, endpoint); 

^작동이되지 않습니다.

로컬 호스트에서는 작동하지만 LAN이나 인터넷에서는 작동하지 않습니다. 방화벽은 서버와 클라이언트 모두에서 꺼져 있습니다. 서버에 접속하려고 할 때 60 초 제한 시간이 있습니다.

+3

진행 방향을 알려주는 [DuplexChannelFactory 클래스] (https://msdn.microsoft.com/en-us/library/ms576164(v=vs.110) .aspx)를 살펴보십시오. . – carlosfigueira

+0

@carlosfigueira 감사합니다. 저는 약간의 변경을가했지만, 지금은 서비스에서 응답을 얻지 못했습니다. "업데이트"를보십시오. 감사! – Daniel

답변

0

클라이언트 연결 경로에 포트 전달이 설정되지 않아 연결 문제가 있음을 발견했습니다. 클라이언트에 대한 적절한 포트 액세스를 보장 할 수 없기 때문에 콜백 모델이 아닌 것으로 되돌아 왔으며 클라이언트의 정기적 인 요청을 사용하여 누적 된 이벤트 데이터를 서비스에서 수신합니다. 아마도 효율적이지는 않지만 지금까지는 작동하지 않는 확실한 방법입니다. 관심을 가져 주셔서 감사합니다.