I have a C# (WPF) application which consumes a particular 3rd party API/tool (let's call this Tool A). My colleagues and I are trying to decouple that from our application, so that it is possible to switch out Tool A in the future, replacing with another vendor's API/tool.
We decided to define a set of interfaces, which would provide the main functionalities of the tool. For every 3rd party API/tool that we want to use to replace Tool A, they would need to implement an adapter (or a set of adapters) that implements the interface(s). This also allows us to use this tool for other projects/applications.
Some of the functionalities provided by Tool A are as non-async (e.g. public Foo DoSomething(Bar bar)) methods. We are considering to define interface methods that provide such functionalities as async method (e.g. Task<Foo> DoSomethingAsync(Bar bar), i.e. Task-returning methods).
That means there are three choices here:
- Define these methods as non-
asynconly. - Define these methods as
asynconly. - Define both non-
asyncandasyncmethods..
Things to consider:
There are also methods which we thought would make sense to be implemented as non-
asyncmethods, but surprisingly the vendor only provided anasyncversion of it.When we force an
asyncmethod to be synchronous (byTask.ResultorTask.Wait()), we are likely to get deadlocks.Non-
asyncmethods can be easily madeasync.Some of the methods are likely to take some time to execute (likely CPU-bound), but that's likely to be between 100-2000ms (i.e. not terribly slow either). Actual result might depend on how the vendor implements it. Implementations of the adapter/interface can choose to:
a. Call the tool's methods synchronously. (e.g.
return Task.FromResult(DoSomething());)b. Wrap with
Task.Run()orTaskFactory.StartNew().I have read this article from Stephen Toub, but I'm not sure whether my case is similar to the
Streamexample.
Example:
public class MainApp
{
private ITool Tool; // Injected in
public Task<Foo> GetFooFromBarAsync(Bar bar)
{
return Tool.DoSomethingAsync(bar);
}
}
public interface ITool
{
Task<Foo> DoSomethingAsync(Bar bar);
}
public class ToolAdapterA : ITool
{
// Private fields of objects of 3rd party API's namespaces
public Task<Foo> DoSomethingAsync(Bar bar)
{
return Task.FromResult(ToolFromVendorA.DoSomething(bar));
}
}
public class ToolAdapterB : ITool
{
// Private fields of objects of second 3rd party API's namespaces
public Task<Foo> DoSomethingAsync(Bar bar)
{
return ToolFromVendorB.ICanDoSomethingInAsync(bar);
}
}
Which of the three choices are most appropriate for my case, based on the considerations I have (+ any other considerations that might be valid)?