3

I have a system that uses System.AddIn (MAF) to host addins in separate processes. Inside the addins I would like to consume some code that leverages async and await.

Since MAF uses remoting to communicate across processes and there is very little control we have over this communication, I am trying to determine the best way to consume the async code without running the risk of hitting a deadlock.

For example, right now I have a contract which defines a method like so:

[AddInContract]
public interface IWorker : IContract
{
    string DoWork(string workToDo);
}

Inside the AddIn implementation of DoWork, I want to be able to consume an async API. It would be great if I could come up with a way of converting from string to Task<string> inside the AddInAdapter and HostAdapter, but I want to be sure that I am not setting myself up for a deadlock.

I would like to define my view contract as:

[System.AddIn.Pipeline.AddInBaseAttribute()]
public interface IWorker
{
    Task<string> DoWork(string workToDo);
}

Then is it safe to do the following inside the contract to view adapter:

public virtual string DoWork(string workToDo)
{
    var t = _view.DoWork(Contracts.AddInSideAdapters.DoWorkAddInAdapter.ContractToViewAdapter(workToDo)).ConfigureAwait(false);
    return t.GetAwaiter().GetResult();
}
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • If your DoWork isn't async, then don't do async... Other wise just `await` and don't use any other async methods (GetAwaiter(), GetResult() .Wait, Result) – Erik Philips Nov 22 '15 at 04:13
  • So, if need to consume an API that only exposes async endpoints, I would simply call `.Result()` on those calls? The reason I am asking is that I would like for someone who is developing an AddIn to not have to think about being async or not. – John Koerner Nov 22 '15 at 04:17
  • 1
    Possible duplicate of [How to call asynchronous method from synchronous method in C#?](http://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c) – Erik Philips Nov 22 '15 at 04:30
  • The little bit of code you've included doesn't seem valid to me. You can't implement `IWorker.DoWork()` that returns `Task` with a method that returns `string`. Also, AFAIK `Task` objects are not remote-able, so I don't see the relevance of your cross-process MEF and async issues to each other. It's very hard to understand what it is you are asking here. Please provide [a good, _minimal_, _complete_ code example](http://stackoverflow.com/help/mcve) that shows clearly what specific problem you are asking about. – Peter Duniho Nov 22 '15 at 04:38
  • @PeterDuniho This is MAF, not MEF. MAF requires 5 DLLs in order to create a MCVE. In MAF there are layers which perform translations between currencies (i.e. converting between a `string` and `Task`). I was hoping someone familiar with MAF and async/await could help answer the question. – John Koerner Nov 22 '15 at 04:42
  • Sorry, you're correct...I misunderstood. Still, I think my point stands. Regardless of context, you can't implement an interface with a method that returns the wrong type, and you can't remote `Task` objects. If it's not possible to create a suitable MCVE, your question may not be appropriate for Stack Overflow. If it is appropriate for Stack Overflow, it seems to me that at the very least, more context is needed to understand what you're asking, as well as more plausible scenarios. – Peter Duniho Nov 22 '15 at 04:46
  • 2
    @PeterDuniho If you understand MAF, then the "view contract" and "contract to view adapter" are concepts that when applied to this question provide enough context to understand how the `Task` gets converted to a `string` in the MAF pipeline. I think this is a very specific and targeted question which is appropriate for StackOverflow, but may be limited to a few people who have the expertise to answer the question. – John Koerner Nov 22 '15 at 05:02
  • Okay...well, I wish you luck. I hope you're right and that you get the answer you're looking for. – Peter Duniho Nov 22 '15 at 05:18
  • 1
    There is no direct way to marshal Task across app domains/process in MAF. If you were to implement the plug-in model yourself then there are few articles that show how to get Task Marshaled across app domains. – Frank Q. May 19 '16 at 17:35

1 Answers1

0

I realize this question is a few months old, but if you are willing to load your AddIn within the same AppDomain as the Host, you'll be able to pass your Task all the way through. I recently just did this and posted my test project on GitHub: https://github.com/middas/AddinProofOfConcept/blob/master/AddinProofOfConcept/ConsoleHost/Program.cs
This is a link to the Host consumer of the AddIn, you'll see the very last test is an asynchronous Task that also has a CancellationToken. The test passes if the Task is cancelled instead of waiting 30 seconds which the AddIn sets up.

Middas
  • 1,862
  • 1
  • 29
  • 44
  • 1
    Thanks for the answer, but one of the big reasons we use MAF is for the process isolation. Loading them in the same AppDomain would be a non-starter for us. – John Koerner Feb 26 '16 at 00:54
  • I figured as much, that tends to be a big reason to go MAF, it was worth pointing this out to other people that may run into this as a possible option. – Middas Feb 26 '16 at 00:59
  • 1
    Loading in the same app domain 3rd party plugins is actually not a good idea. While I understand it does simplify development it comes with a cost which is risk. – Frank Q. May 20 '16 at 03:23