2
\$\begingroup\$

My goal is to grab some data inside asp.net core app on server from external source via wcf service. In future i would like wcf responses to be cached on server and provide asp.net app clients "normal" errors if they appear. Some things to notice: I'm using .net core 2.0 and generated wcf service proxy with a help of WCF Connected Service extension. Wcf service is hosted as windows service and exposed via BasicHttpBinding.

First of all, after going through WCF Connected Service wizard, I have IMyWcfService contract and MyWcfServiceClient proxy:

public interface IMyWcfService
{
    Task<GroupWorkout[]> GetGroupScheduleForCurrentWeekAsync();
}

public partial class MyWcfServiceClient : ClientBase<IMyWcfService>, IMyWcfService
{
    ...
    public Task<GroupWorkout[]> GetGroupScheduleForCurrentWeekAsync()
    {
        return base.Channel.GetGroupScheduleForCurrentWeekAsync();
    }
    ...
}

Next, i'm wrapping service calls like this:

public class MyWcfServiceClientHelper : IMyWcfServiceClientHelper
{
    private readonly MyWcfServiceClient _client;

    public MyWcfClientHelper(MyWcfServiceClient client)
    {
        _client = client;
    }

    public async Task<ActionResponse<T>> Call<T>(Expression<Func<IMyWcfService, Task<T>>> expression)
    {
        var result = new ActionResponse<T>();

        try
        {
            result.Result = await expression.Compile()(_client);
        }
        catch (FaultException<MyWcfServiceFault> fault)
        {
            result.Error = new ActionError() { Code = ErrorCodes.WcfExpectedFault, Message = fault.Message };
        }
        catch (CommunicationException ex)
        {
            result.Error = new ActionError() { Code = ErrorCodes.WcfCommunicationError, Message = ex.Message };
            _client.Abort();
        }
        catch (TimeoutException ex)
        {
            result.Error = new ActionError() { Code = ErrorCodes.WcfTimeoutError, Message = ex.Message };
            _client.Abort();
        }
        catch (Exception ex)
        {
            result.Error = new ActionError() { Code = ErrorCodes.UnknownError, Message = ex.Message };
            _client.Abort();

            throw;
        }

        return result;
    }
}

DI regs are:

public static class IServiceCollectionExtensions
{
    public static IServiceCollection AddConnectedServices(this IServiceCollection coll)
    {
        coll.AddScoped<MyWcfServiceClient>();
        coll.AddScoped<IMyWcfServiceClientHelper, MyWcfServiceClientHelper>();

        return coll;
    }
}

And call it like this:

public class ScheduleUnit : IScheduleUnit
{
    private readonly IMyWcfServiceClientHelper _helper;

    public ScheduleUnit(IMyWcfServiceClientHelper helper)
    {
        _helper = helper;
    }

    public async Task<ActionResponse<GroupWorkout[]>> Get()
    {
        //here also will be some logic to resolve where to get data (cache or service call)
        ...
        var data = await _helper.Call(u => u.GetGroupScheduleForCurrentWeekAsync());
        ...
    }
}

ActionResponse, ActionError is my custom classes:

public class ActionResponse<T> : IActionResponse
{
    public T Result { get; set; }

    public bool IsCorrect => Error == null;

    public ActionError Error { get; set; }
}

So, is it ok to recreate service (scoped registration) and not call it if cache is valid? Maybe singleton registration suits more in this case? Is there any cons of using helper there? Do Func> parameter for expression is ok? I mean asynchronous call:

await expression.Compile()(_client);

May be you could consider something else to improve with that code? Thanks in advance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.