2017-03-01 30 views
5

Aktualnie pracuję nad projektem, w którym muszę zarządzać aplikacją za pomocą klienta wcf. Problem, przed którym stoję, polega na tym, że po wykonaniu połączenia z serwerem potrzebuję, aby klient oczekiwał na wywołanie zwrotne. Oto scenariusz:Spraw, aby klient wcf czekał na oddzwonienie

Wykonuję połączenie z usługą, która pokazuje okno, a następnie aplikacja serwera jest bezczynna. Kiedy klikam przycisk w oknie, wywołuje ono oddzwanianie do klienta. w tym czasie interfejs użytkownika klienta musi być wyłączony - musi czekać na oddzwonienie. Czy możesz mi powiedzieć, jak mogę to osiągnąć? Czy ma coś wspólnego z trybem współbieżności lub atrybutem kontraktu operacyjnego?

To jest mój kod na ServiceContract i CallbackContract:

[ServiceContract(CallbackContract = typeof(IWCFServiceCallback))] 
public interface IWCFService 
{ 
    [OperationContract] 
    void OpenWindow(); 
} 
public interface IWCFServiceCallback 
{ 
    [OperationContract(IsOneWay = true)] 
    void ReturnValue(object[] value); 
} 

Odpowiedz

0

Dzięki za odpowiedzi. Rozwiązałem problem za pomocą funkcji Win32 ShowWindow.

1

Nie można opisać funkcja nie ma nic wspólnego z trybem Współbieżnym lub funkcjonowania umowy. Prawdopodobnie musisz zaimplementować tę funkcję za pomocą semaforów (Mutex, Monitor, niezależnie od ...) i wywołań zwrotnych od serwera do klienta, aby ustawić semafor.

Powiedziawszy, że opisywana przez ciebie funkcjonalność wydaje się naprawdę dziwna.

1

Można to zrobić, wdrażając asynchroniczną operację usługi i wywołując ją przy użyciu Async/Await.

Wyłącz interfejs użytkownika klienta tuż przed wywołaniem usługi, a następnie włącz ją po powrocie wywołania zwrotnego.

https://msdn.microsoft.com/en-us/library/ms731177.aspx

using System; 
using System.Collections.Generic; 
using System.ServiceModel; 
using System.Text; 
using System.Threading; 

namespace Microsoft.WCF.Documentation 
{ 
    [ServiceContractAttribute(Namespace="http://microsoft.wcf.documentation")] 
    public interface ISampleService{ 

    [OperationContractAttribute] 
    string SampleMethod(string msg); 

    [OperationContractAttribute(AsyncPattern = true)] 
    IAsyncResult BeginSampleMethod(string msg, AsyncCallback callback, object asyncState); 

    //Note: There is no OperationContractAttribute for the end method. 
    string EndSampleMethod(IAsyncResult result); 

    [OperationContractAttribute(AsyncPattern=true)] 
    IAsyncResult BeginServiceAsyncMethod(string msg, AsyncCallback callback, object asyncState); 

    // Note: There is no OperationContractAttribute for the end method. 
    string EndServiceAsyncMethod(IAsyncResult result); 
    } 

    public class SampleService : ISampleService 
    { 
    #region ISampleService Members 

    public string SampleMethod(string msg) 
    { 
     Console.WriteLine("Called synchronous sample method with \"{0}\"", msg); 
     return "The sychronous service greets you: " + msg; 
    } 

    // This asynchronously implemented operation is never called because 
    // there is a synchronous version of the same method. 
    public IAsyncResult BeginSampleMethod(string msg, AsyncCallback callback, object asyncState) 
    { 
     Console.WriteLine("BeginSampleMethod called with: " + msg); 
     return new CompletedAsyncResult<string>(msg); 
    } 

    public string EndSampleMethod(IAsyncResult r) 
    { 
     CompletedAsyncResult<string> result = r as CompletedAsyncResult<string>; 
     Console.WriteLine("EndSampleMethod called with: " + result.Data); 
     return result.Data; 
    } 

    public IAsyncResult BeginServiceAsyncMethod(string msg, AsyncCallback callback, object asyncState) 
    { 
     Console.WriteLine("BeginServiceAsyncMethod called with: \"{0}\"", msg); 
     return new CompletedAsyncResult<string>(msg); 
    } 

    public string EndServiceAsyncMethod(IAsyncResult r) 
    { 
     CompletedAsyncResult<string> result = r as CompletedAsyncResult<string>; 
     Console.WriteLine("EndServiceAsyncMethod called with: \"{0}\"", result.Data); 
     return result.Data; 
    } 
    #endregion 
    } 

    // Simple async result implementation. 
    class CompletedAsyncResult<T> : IAsyncResult 
    { 
    T data; 

    public CompletedAsyncResult(T data) 
    { this.data = data; } 

    public T Data 
    { get { return data; } } 

    #region IAsyncResult Members 
    public object AsyncState 
    { get { return (object)data; } } 

    public WaitHandle AsyncWaitHandle 
    { get { throw new Exception("The method or operation is not implemented."); } } 

    public bool CompletedSynchronously 
    { get { return true; } } 

    public bool IsCompleted 
    { get { return true; } } 
    #endregion 
    } 
} 
+0

Dzięki za odpowiedź. Dodam tylko, że po wywołaniu metody chcę, aby klient działał tak samo, jak gdyby sama metoda zwracała wartość (bez wywołania zwrotnego) - klient czeka, aż usługa zakończy pracę i zwróci wartość. Nie mogę zablokować interfejsu użytkownika ręcznie, ponieważ klient jest dodatkiem Excel, który nie ma formularzy/okien, które mógłbym wyłączyć. – Bartek

+0

Wywołanie usługi jest wykonywane, gdy program Excel ma otwarty interfejs FunctionWizard, więc nie mogę po prostu zablokować komórek, ponieważ powoduje to awarię programu Excel. – Bartek

+0

@Bartek - To inny problem niż oddzielne pytania i odpowiedzi. Uważam, że dostarczyłem odpowiedź na to pytanie, ale jeśli nie, daj mi znać, a postaram się pomóc. FYI zauważ, że Microsoft w swoim przykładowym kodzie tutaj zboczył z własnych [zalecanych konwencji nazewnictwa] (https://msdn.microsoft.com/en-us/library/mt674882.aspx#Anchor_7). Funkcje asynchroniczne powinny mieć dołączone "Asynchroniczne" do ich nazw. To prawda, że ​​nie widzimy tutaj słowa kluczowego 'async', ale jest to architektura asynchroniczna. – InteXX

1

Gdy concurrenymode jest ConcurrencyMode.Single a klient wywołuje usługę, usługa będzie stworzyć blokadę. Kiedy wywoła interfejs wywołania zwrotnego z IsOneWay jest fałszywy, komunikat o wyniku zostanie odesłany do usługi. Usługa utworzy blokadę ponownie i zablokuje się, ponieważ blokada jest wstrzymana z połączenia klienta. Z ConsurrencyMode. Reentrant zamek zostanie podstępnie zwolniony, gdy oddzwonisz i ponownie otrzymasz po powrocie, abyś mógł z niego skorzystać. IsOneWay = true to również rozwiązanie, ponieważ nie odesłano komunikatu o wyniku.

więc powinieneś być w stanie zablokować Ci GUI tuż przed wywołaniem usługi i odblokować go w zwrotnego, gdy operacja wywołania zwrotnego ma IsOneWay = true lub usługa ma ConcurrencyMode.Reentrant skonfigurowany

+0

Problem polega na tym, że nie mogę ręcznie zablokować interfejsu użytkownika klienta, ponieważ jest to dodatek do programu Excel z otwartą funkcją FunctionWizard. Jeśli spróbuję zablokować komórki, program Excel ulega awarii. – Bartek

Powiązane problemy