I am writing the client side for a WCF service that supports both synchronous and asynchronous calls without having to implement 5-6 different methods in channel for each method in the contract.
I have a base interface (IServiceClient) and a generic class based on this interface type (ServiceClient) as follows:
public interface IServiceClient { /* nothing here -- just for casting purpose */ }
public abstract class ServiceClient<TChannel> : ClientBase<TChannel> where TChannel : class, IServiceClient
{
....
public T SyncCall<T>(string method, object[] args)
{
....
return (T)...
}
public ServiceCall<T> AsyncCall<T>(string method, object[] args)
{
return new ServiceCall<T>(this, method, args);
}
....
public class ServiceCall<T>
{
public ServiceCall(RemoteServiceClient<TChannel> service, string method, object[] args)
{
...
}
...
public PageAsyncTask CreatePageAsyncTask(Action<T> onSuccess, Action<Exception> onFailure)
{
return new System.Web.UI.PageAsyncTask(...);
}
}
}
Also, have another interface (actual contract) extending the base interface and a specific implementation of the ServiceClient class based on the derived interface as follows:
[ServiceContract]
public interface IMyServiceClient : IServiceClient
{
....
[OperationContract]
string GetWhatever(int index);
[OperationContract]
IAsyncResult BeginGetWhatever(int index, System.AsyncCallback callback, object asyncState);
string EndGetWhatever(System.IAsyncResult result);
....
}
public partial class MyServiceClient : ServiceClient<IMyServiceClient>
{
....
public string GetWhatever(int index)
{
return SyncCall<string>("GetWhatever", new object[] { index });
}
public ServiceCall<string> GetWhateverAsync(int index)
{
return AsyncCall<string>("GetWhatever", new object[] { index });
}
....
}
I try to call the GetWhatever(int) method asynchronously in my control as follows:
public class MyWebControl : WebControl
{
private void HandleFailure(System.Exception e) { .... }
public void CallService<T>(ServiceClient<IServiceClient>.ServiceCall<T> func, System.Action<T> onSuccess, System.Action<Exception> onFailure)
{
this.Page.RegisterAsyncTask(func.CreatePageAsyncTask(onSuccess, onFailure ?? (e => this.HandleFailure(e))));
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
....
var client = new MyServiceClient(/*whatever*/);
client.Open();
CallService(client.GetWhateverAsync(index), this.OnResult, this.OnError);
....
}
public void OnResult(string result) { .... }
public void OnError(Exception e) { .... }
}
I get 2 compilation errors:
Error 1 The best overloaded method match for 'MyWebControl.CallService<string>>(IServiceClient>.ServiceCall<string>, System.Action<string>, System.Action<System.Exception>)' has some invalid arguments
Error 2 Argument 1: cannot convert from 'ServiceClient<IMyServiceClient>.ServiceCall<string>' to 'ServiceClient<IServiceClient>.ServiceCall<string>'
Apparently the compiler can't seem to figure out that IMyServiceClient extends IServiceClient. I understand that the interface inheritance doesn't work like class inheritance; but I am not sure how to work around this compiler error. I already tried adding a new ServiceCall implementation inside MyServiceClient class to extend that in base -- but the compiler error hasn't changed.
BTW, if I change my ServiceClient implementation to base off of IMyServiceClient, it works. Also, calling just client.GetWhatever(index) (which calls SyncCall method) compiles and works just fine.
Any idea of what's going on or what the compiler is looking for would help. Thanks.