I wrote a WCF client that I want to consume in my asp.net core service (the client was written based on this post):
public class ExternalCompanyClient : IExternalCompanyClient
{
public async Task<string> CallAsync()
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(new Uri("http://........."));
ChannelFactory<IExternalCompanyService> factory = new ChannelFactory<IExternalCompanyService>(basicHttpBinding, endpointAddress);
IExternalCompanyService serviceProxy = factory.CreateChannel();
((ICommunicationObject)serviceProxy).Open();
var opContext = new OperationContext((IClientChannel)serviceProxy);
var prevOpContext = OperationContext.Current;
OperationContext.Current = opContext;
ExternalCompanyResponse ret = null;
var request = GetRequest();
try
{
ret = await serviceProxy.GetCompanyInfoAsync(request);
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
WCFHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
OperationContext.Current = prevOpContext;
}
return ret;
}
}
After that, I just need to register this service via dependency injection:
public static IServiceCollection AddExternalCompanyClient(this IServiceCollection services) =>
services.AddTransient<IExternalCompanyClient, ExternalCompanyClient>();
Now what I want to do is to move on all common code into separate ServiceCaller class and use this class for all other WCF clients for the usability purposes.
So, the ServiceCaller is as follows (I added the comments to see the differences in CallAsync method):
internal class ServiceCaller<TInterface, TIn, TOut> where TInterface : IService<TIn, TOut>
{
private readonly Uri _uri;
public ServiceCaller(Uri uri)
{
var attributes = typeof(TInterface).GetCustomAttributes(typeof(ServiceContractAttribute), true);
if (attributes.Length == 0)
{
throw new ArgumentException($"Interface {typeof(TInterface).Name} does not have ServiceContract attribute");
}
_uri = uri;
}
public async Task<TOut> CallAsync(TIn request, TOut valueIfError = default(TOut))
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(_uri); // uri is passed into via a constructor
ChannelFactory<TInterface> factory = new ChannelFactory<TInterface>(basicHttpBinding, endpointAddress);
TInterface serviceProxy = factory.CreateChannel(); // now the serviceProxy is of type of TInterface
((ICommunicationObject)serviceProxy).Open();
var opContext = new OperationContext((IClientChannel)serviceProxy);
var prevOpContext = OperationContext.Current;
OperationContext.Current = opContext;
TOut ret = default(TOut); // the return has TOut type now
try
{
ret = await serviceProxy.InvokeAsync(request); // and here I invoke the interface method
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
CloseCommunicationObjects.CloseOrAbort((ICommunicationObject)serviceProxy, factory);
OperationContext.Current = prevOpContext;
}
return ret;
}
}
So, I added IService interface:
public interface IService<TIn, TOut>
{
Task<TOut> InvokeAsync(TIn request);
}
And, finally, my new simplified ExternalCompanyClient:
public class ExternalCompanyClient : IExternalCompanyClient, IService<ExternalCompanyRequest, ExternalCompanyResponse>
{
private readonly IExternalCompanyService _externalCompanyService;
public ExternalCompanyClient(IExternalCompanyService externalCompanyService)
{
_externalCompanyService = externalCompanyService;
}
private ExternalCompanyRequest GetRequest() => // some logic goes here
public async Task<string> GetCompanyInfoAsync()
{
var request = GetRequest();
var serviceCaller = new ServiceCaller<ExternalCompanyClient, ExternalCompanyRequest, ExternalCompanyResponse>(
new System.Uri("http://......................."));
var result = await serviceCaller.CallAsync(request);
return result;
}
public Task<ExternalCompanyResponse> InvokeAsync(ExternalCompanyRequest request)
{
return _externalCompanyService.GetCompanyInfoAsync(request);
}
}
How should I register dependencies for the ExternalCompanyClient in that case?