PowerShell System.Management.Automation.Runspaces vs TAP in C# - c#

I've recently run into a use case where the "Async" suffix recommended by the .NET Task-based Asynchronous Pattern (TAP) conflicts with what's already in existence.
I'm dealing with System.Management.Automation.Runspaces.Runspace during the course of attempting PowerShell remoting to execute cmdlets as part of my app.
Ignoring the questions that arise around whether it's best practice to knock-up a remoting session each time you want to run a cmdlet (for an enterprise scale application this might be a lot) or to create a connection and attempt to maintain it during the app's lifetime (with reconnection logic)...
My application is based on TAP which proliferates from the WebApi2 controller all the way down to the backend, what I'm trying to do is asynchronously open a Runspace connection - but noticed that there's already an OpenAsync method which isn't awaitable and returns void - which is like some weird mash-up between async void (for event handlers), void (non-async) and the Async suffix.
I'm using Stephen Cleary's Nito.AsyncEx nuget package to provide me with a AsyncAutoResetEvent which I can asynchronously await before attempting connection/reconnection).
The question is: should I care about the fact that my code really isn't going to be properly "async" in using either Open or OpenAsync on the Runspace?
If I should care - what's the best practice in this situation? It doesn't look like Microsoft have released updated DLLs which provide awaitable Open methods for the Runspace. Strangely despite MS giving information on how to use these libraries, they've added the caveat on the nuget site:
Versions 6.1.7601.* are unofficial packages for .Net 4.0 and are not
supported by Microsoft.
There also seems to be this DLL-esque package on nuget from Microsoft, aagggghh!
Currently my plan is something akin to this:
public async Task<Result> StartAsync()
{
if (!IsConnected)
{
try
{
await _asyncRunspaceLock.WaitAsync();
if (!IsConnected)
{
var protocol = IsHttpsEnabled ? "https" : "http";
var serverUrl = $"{protocol}://{Fqdn}/OcsPowershell";
var uri = new Uri(serverUrl);
var connectionInfo = new WSManConnectionInfo(uri, ShelUri, PSCredential.Empty)
{
SkipRevocationCheck = true,
};
var runspace = runspaceFactory.CreateRunspace(connectionInfo);
runspace.OpenAsync();
}
}
catch (Exception ex)
{
// TODO: Handle logging the 3rd party exception at the lowest level.
return Result.Fail(ex.Message);
}
finally
{
_asyncRunspaceLock.Set();
}
}
return Result.Ok();
}
It's a work in progress, I guess the same issue crops up around the RunspaceFactory's CreateRunspace static method which isn't async (at least it isn't named with the Async suffix).
Any helpful advice or experience would be greatly appreciated.
Thanks
peteski

From the documentation:
If you're adding a TAP method to a class that already contains that method name with the Async suffix, use the suffix TaskAsync instead. For example, if the class already has a GetAsync method, use the name GetTaskAsync.

Related

Is Oracle OpenAsync etc... not a truly async method?

I have an Oracle database that I am accessing through ODP.NET
This is my demo code
public static async Task<Field[][]> ReadAsync(string ExtractSql)
{
var connStr = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
List<Field[]> ret = new List<Field[]>();
using (OracleConnection conn = new OracleConnection(connStr))
{
await conn.OpenAsync();
}
return ret.ToArray();
}
This code does not behave as async, the UI is completely blocked for seconds.
If I simply replace
await Task.Delay(10000); //conn.OpenAsync();
all works fine as expected.
Can I conclude that this is a bug in ODP.NET, is there a github repo or where can I report it or am I missing something trivial in C# async?
Is there anyone else using .NET for Oracle and experiencing a similar issue for async methods?
Please note
Of course I've added the code inside to open the command and read the data and the issue persists, here I'm showing the minimal amount of code that is sufficient to detect the problem. E.g. I have a firewall that can block the connection and in that case it times out, therefore the only "open" command can be enough to make the app stuck, if the db part is not async.
Thank you to #madreflection for the comments. I'm really happy to delete my answer and accept an answer from him, as I kindly asked.
Anyway, now it is clear by looking at Visual Studio intellisense that those async methods are not there but they are symply inherited from the generic System.Data.Common.DbConnection.
I should have also understood it at the first method that is not returning a Task or a Task<bool>, i.e. from the following line
OracleDataReader DR = (OracleDataReader) await cmd.ExecuteReaderAsync();
where I was forced to add an unexpected cast (now I understand why).
I'm going to wrap the API in a Task.Run because I can't block my UI.
See below the screenshot with the mouse over the OpenAsync.
From the doc you can read
This is the asynchronous version of Open(). Providers should override with an appropriate implementation
The default implementation invokes the synchronous Open() call and returns a completed task.
My person opinion is that the default implementation is doing the wrong/misleading thing, I would have rather preferred an exception "not implemented" thrown instead.

Using Google API GoogleJsonWebSignature.ValidateAsync(...) in server call

I am trying to implement Google SSO in my C# web application. It seemed to be pretty straightforward. Based on this tutorial, Google does its magic in the web browser to get an Id_Token JWT. I pass the token is passed it to my web service for validation and use it to match it to a user in the application.
Although I am not sure if my approach with the server-side Google API is correct yet, my big hangup is trying to figure out how to work with the async call in the Google API to see what I get back.
My code is pretty simple using the Google.Apis.Auth namespace:
public async Task<GoogleJsonWebSignature.Payload> wfValidateAsync(string pId_Token)
{
GoogleJsonWebSignature.Payload Sig = await GoogleJsonWebSignature.ValidateAsync(pId_Token, null, false);
return Sig;
}
Although brand new to this async/await paradigm, I do have some experience in AngularJS / NodeJS promises / callbacks. My challenge is that it seems async methods can only be called by other async methods all the way back up the call-stack. I think it means ending the service call before the async response finishes and the service can act on the result.
Also, for creating unit tests, putting async into the [TestMethod] method makes it completely disappear from the test explorer. I'm not sure how to test/debug this conundrum.
Thanks in advance to anyone who can help me screw my head back on straight with this.
Although brand new to this async/await paradigm, I do have some experience in AngularJS / NodeJS promises / callbacks.
But not use Typescript, right?
My challenge is that it seems async methods can only be called by other async methods all the way back up the call-stack.
They should. Bad things can happen if you don't.
I think it means ending the service call before the async response finishes and the service can act on the result.
No! The compiler generates a state machine for methods with the async modifier and the await keyword means "go do something else and I'll come back here when I'm done".
Also, for creating unit tests, putting async into the [TestMethod] method makes it completely disappear from the test explorer. I'm not sure how to test/debug this conundrum.
You're probably making your test methods async void. They should be async Task in order for the test engine to know when the test is done.
Have a look at Stephen Cleary's blog. He has lots of content on async-await.
Paulo, Thank you!!
I was able to get this working with your advice on the last part about the test method. I had to change this:
//THIS TEST METHOD DOESN'T SHOW IN THE TEST EXPLORER
[TestMethod]
public async void AuthenticateGoogle()
{
string lToken = "[JWT TOKEN HERE]";
wfUser lUser = new wfUser(_wfContext);
var lAuthenticateResult = await lUser.wfAuthenticateGoogle(lToken);
Assert.IsTrue(lAuthenticateResult, "JWT Token Validated");
}
To this:
//THIS TEST METHOD SHOWS IN THE TEST EXPLORER
[TestMethod]
public async Task AuthenticateGoogle()
{
string lToken = "[JWT TOKEN HERE]";
wfUser lUser = new wfUser(_wfContext);
var lAuthenticateResult = await lUser.wfAuthenticateGoogle(lToken);
Assert.IsTrue(lAuthenticateResult, "JWT Token Validated");
}
NOW -- as an additional gotcha that was hanging me up, this will also cause a unit test to disappear from the test explorer, which I found out through lazy copy/pasting a non-test method's definition and mindlessly just adding a return when the build output told me I needed to return a value.
//THIS TEST METHOD DOESN'T SHOW IN THE TEST EXPLORER DUE TO RETURN VALUE
[TestMethod]
public async Task<bool> AuthenticateGoogle()
{
string lToken = "[JWT TOKEN HERE]";
wfUser lUser = new wfUser(_wfContext);
var lAuthenticateResult = await lUser.wfAuthenticateGoogle(lToken);
Assert.IsTrue(lAuthenticateResult, "JWT Token Validated");
return true;
}
In addition to the excellent blog you shared, this article from MSDN Magazine entitled Async Programming : Unit Testing Asynchronous Code helped me get my brain around it too.
What was hanging me up with all of this was mixing synchronous and async methods which, to your point, was not working well. The code seemed to skip the debug points I had set after the await calls as if it never ran them or, if it did run them, ran them somewhere I could not see and couldn't log to the debugger.
It was one of those terrible moments late on a Friday night where a developer starts to question both competence and sanity! :)
Thanks again for the help!
p.s. I incorrectly typed Angular JS in my question and meant Angular 4...and I am using TypeScript there. Some day I'll stop incorrectly referring the newer versions of Angular as AngularJS.
My challenge is that it seems async methods can only be called by other async methods all the way back up the call-stack.
It's not entirely true. You can use async method in sync methods. Of course you are losing most of the 'async' effect, but sometimes you have to. As async methods returs tasks you have some options.
When Task is returning result, any reference to t.Result will block execution till it's known. Another option is to use Task.Wait(preferably with timeout). For example code to validate google jwt token:
public bool ValidateGoogleToken(string token)
{
try
{
if(GoogleJsonWebSignature.ValidateAsync(token).Wait(1000))
return true; //success
//timeout exceeded
}
catch (Exception e)
{
//tampered token
}
return false;
}

HttpClient in an NLog target

I need to create a Target that uses HttpClient. HttpClient does not contain any synchronous methods, they are all Task returning Async calls. What is the best way to use this in an NLog target, seeing as the api does not seem to be async/await aware?
Update NLog 4.6
NLog 4.6 introduces AsyncTaskTarget that ensures correct ordering, and also makes it easy to perform batching.
Old answer:
Maybe something like this should work:
public class CustomTarget : Target
{
protected override async void Write(NLog.Common.AsyncLogEventInfo logEvent)
{
try
{
await WriteAsync(logEvent.LogEvent).ConfigureAwait(false);
logEvent.Continuation(null);
}
catch (Exception ex)
{
InternalLogger.Error(ex, "Failed to sent message");
logEvent.Continuation(ex);
}
}
}
Or steal the code from this PR: https://github.com/NLog/NLog/pull/2006
If you want to make things simple then you can just do a Wait() on the async-task. Then just wrap your custom-target using the AsyncTargetWrapper. Then you also don't have to worry about having too many active http-requests.
But NLog has no issue with targets that performs deferred log write-operations. The only required contract is that the async-continuation provided together with the LogEventInfo is called after the deferred log-write-operation has finally completed (Maybe look at the NetworkTarget for for some inspiration)
I have implemented httpclient with aysnc-wrapper target.
You can install and use it from nuget package
https://www.nuget.org/packages/NLog.HttpClient

LiveAuthClient InitializeAsync hangs

I am having trouble with a demo from msdn
The demo
On the method updateUserName:
public static async Task updateUserName(TextBlock userName, Boolean signIn)
{
try
{
// Open Live Connect SDK client.
LiveAuthClient LCAuth = new LiveAuthClient();
LiveLoginResult LCLoginResult = await LCAuth.InitializeAsync();
try
{
//this is never reached
LiveLoginResult loginResult = null;
if (signIn)
......
the code hangs at ht InitialuzeAsync() method and never enters the try statement. Can someone who has used the live SDK please tell me what migh be wrong? The code is a direct copy-paste from the demo and the live SDK was installed via NuGet on VS2012.
I predict that you are calling Task.Wait or Task<T>.Result somewhere further up your call stack. As I describe on my blog, you are causing a deadlock because the await is attempting to resume on the UI thread.
The correct solution is to use await "all the way", which is one of the best practices I describe in my article. If you have a situation where you think you "can't" use await, then take a look at my async/OOP blog series, which describes various code patterns for async code, most notably constructors and properties.
Seems you have to associate your app with the store to use this feature, or else it hangs. After associating it, everything started working.

Java Equivalent of C# async/await?

I am a normal C# developer but occasionally I develop application in Java. I'm wondering if there is any Java equivalent of C# async/await?
In simple words what is the java equivalent of:
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
return urlContents.Length;
}
No, there isn't any equivalent of async/await in Java - or even in C# before v5.
It's a fairly complex language feature to build a state machine behind the scenes.
There's relatively little language support for asynchrony/concurrency in Java, but the java.util.concurrent package contains a lot of useful classes around this. (Not quite equivalent to the Task Parallel Library, but the closest approximation to it.)
The await uses a continuation to execute additional code when the asynchronous operation completes (client.GetStringAsync(...)).
So, as the most close approximation I would use a CompletableFuture<T> (the Java 8 equivalent to .net Task<TResult>) based solution to process the Http request asynchronously.
UPDATED on 25-05-2016 to AsyncHttpClient v.2 released on Abril 13th of 2016:
So the Java 8 equivalent to the OP example of AccessTheWebAsync() is the following:
CompletableFuture<Integer> AccessTheWebAsync()
{
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
return asyncHttpClient
.prepareGet("http://msdn.microsoft.com")
.execute()
.toCompletableFuture()
.thenApply(Response::getResponseBody)
.thenApply(String::length);
}
This usage was taken from the answer to How do I get a CompletableFuture from an Async Http Client request?
and which is according to the new API provided in version 2 of AsyncHttpClient released on Abril 13th of 2016, that has already intrinsic support for CompletableFuture<T>.
Original answer using version 1 of AsyncHttpClient:
To that end we have two possible approaches:
the first one uses non-blocking IO and I call it AccessTheWebAsyncNio. Yet, because the AsyncCompletionHandler is an abstract class (instead of a functional interface) we cannot pass a lambda as argument. So it incurs in inevitable verbosity due to the syntax of anonymous classes. However, this solution is the most close to the execution flow of the given C# example.
the second one is slightly less verbose however it will submit a new Task that ultimately will block a thread on f.get() until the response is complete.
First approach, more verbose but non-blocking:
static CompletableFuture<Integer> AccessTheWebAsyncNio(){
final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
final CompletableFuture<Integer> promise = new CompletableFuture<>();
asyncHttpClient
.prepareGet("https://msdn.microsoft.com")
.execute(new AsyncCompletionHandler<Response>(){
#Override
public Response onCompleted(Response resp) throws Exception {
promise.complete(resp.getResponseBody().length());
return resp;
}
});
return promise;
}
Second approach less verbose but blocking a thread:
static CompletableFuture<Integer> AccessTheWebAsync(){
try(AsyncHttpClient asyncHttpClient = new AsyncHttpClient()){
Future<Response> f = asyncHttpClient
.prepareGet("https://msdn.microsoft.com")
.execute();
return CompletableFuture.supplyAsync(
() -> return f.join().getResponseBody().length());
}
}
async and await are syntactic sugars. The essence of async and await is state machine. The compiler will transform your async/await code into a state machine.
At the same time, in order for async/await to be really practicable in real projects, we need to have lots of Async I/O library functions already in place. For C#, most original synchronized I/O functions has an alternative Async version. The reason we need these Async functions is because in most cases, your own async/await code will boil down to some library Async method.
The Async version library functions in C# is kind of like the AsynchronousChannel concept in Java. For example, we have AsynchronousFileChannel.read which can either return a Future or execute a callback after the read operation is done. But it’s not exactly the same. All C# Async functions return Tasks (similar to Future but more powerful than Future).
So let’s say Java do support async/await, and we write some code like this:
public static async Future<Byte> readFirstByteAsync(String filePath) {
Path path = Paths.get(filePath);
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(100_000);
await channel.read(buffer, 0, buffer, this);
return buffer.get(0);
}
Then I would imagine the compiler will transform the original async/await code into something like this:
public static Future<Byte> readFirstByteAsync(String filePath) {
CompletableFuture<Byte> result = new CompletableFuture<Byte>();
AsyncHandler ah = new AsyncHandler(result, filePath);
ah.completed(null, null);
return result;
}
And here is the implementation for AsyncHandler:
class AsyncHandler implements CompletionHandler<Integer, ByteBuffer>
{
CompletableFuture<Byte> future;
int state;
String filePath;
public AsyncHandler(CompletableFuture<Byte> future, String filePath)
{
this.future = future;
this.state = 0;
this.filePath = filePath;
}
#Override
public void completed(Integer arg0, ByteBuffer arg1) {
try {
if (state == 0) {
state = 1;
Path path = Paths.get(filePath);
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(100_000);
channel.read(buffer, 0, buffer, this);
return;
} else {
Byte ret = arg1.get(0);
future.complete(ret);
}
} catch (Exception e) {
future.completeExceptionally(e);
}
}
#Override
public void failed(Throwable arg0, ByteBuffer arg1) {
future.completeExceptionally(arg0);
}
}
There is no equivalent of C# async/await in Java at the language level. A concept known as Fibers aka cooperative threads aka lightweight threads could be an interesting alternative. You can find Java libraries providing support for fibers.
Java libraries implementing Fibers
JetLang
Kilim
Quasar
You can read this article (from Quasar) for a nice introduction to fibers. It covers what threads are, how fibers can be implemented on the JVM and has some Quasar specific code.
As it was mentioned, there is no direct equivalent, but very close approximation could be created with Java bytecode modifications (for both async/await-like instructions and underlying continuations implementation).
I'm working right now on a project that implements async/await on top of JavaFlow continuation library, please check https://github.com/vsilaev/java-async-await
No Maven mojo is created yet, but you may run examples with supplied Java agent. Here is how async/await code looks like:
public class AsyncAwaitNioFileChannelDemo {
public static void main(final String[] argv) throws Exception {
...
final AsyncAwaitNioFileChannelDemo demo = new AsyncAwaitNioFileChannelDemo();
final CompletionStage<String> result = demo.processFile("./.project");
System.out.println("Returned to caller " + LocalTime.now());
...
}
public #async CompletionStage<String> processFile(final String fileName) throws IOException {
final Path path = Paths.get(new File(fileName).toURI());
try (
final AsyncFileChannel file = new AsyncFileChannel(
path, Collections.singleton(StandardOpenOption.READ), null
);
final FileLock lock = await(file.lockAll(true))
) {
System.out.println("In process, shared lock: " + lock);
final ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.size());
await( file.read(buffer, 0L) );
System.out.println("In process, bytes read: " + buffer);
buffer.rewind();
final String result = processBytes(buffer);
return asyncResult(result);
} catch (final IOException ex) {
ex.printStackTrace(System.out);
throw ex;
}
}
#async is the annotation that flags a method as asynchronously executable, await() is a function that waits on CompletableFuture using continuations and a call to "return asyncResult(someValue)" is what finalizes associated CompletableFuture/Continuation
As with C#, control flow is preserved and exception handling may be done in regular manner (try/catch like in sequentially executed code)
Java itself has no equivalent features, but third-party libraries exist which offer similar functionality, e.g.Kilim.
Java doesn't have direct equivalent of C# language feature called async/await, however there's a different approach to the problem that async/await tries to solve. It's called project Loom, which will provide virtual threads for high-throughput concurrency. It will be available in some future version of OpenJDK.
This approach also solves "colored function problem" that async/await has.
Similar feature can be also found in Golang (goroutines).
First, understand what async/await is. It is a way for a single-threaded GUI application or an efficient server to run multiple "fibers" or "co-routines" or "lightweight threads" on a single thread.
If you are ok with using ordinary threads, then the Java equivalent is ExecutorService.submit and Future.get. This will block until the task completes, and return the result. Meanwhile, other threads can do work.
If you want the benefit of something like fibers, you need support in the container (I mean in the GUI event loop or in the server HTTP request handler), or by writing your own.
For example, Servlet 3.0 offers asynchronous processing. JavaFX offers javafx.concurrent.Task. These don't have the elegance of language features, though. They work through ordinary callbacks.
There isn't anything native to java that lets you do this like async/await keywords, but what you can do if you really want to is use a CountDownLatch. You could then imitate async/await by passing this around (at least in Java7). This is a common practice in Android unit testing where we have to make an async call (usually a runnable posted by a handler), and then await for the result (count down).
Using this however inside your application as opposed to your test is NOT what I am recommending. That would be extremely shoddy as CountDownLatch depends on you effectively counting down the right number of times and in the right places.
I make and released Java async/await library.
https://github.com/stofu1234/kamaitachi
This library don't need compiler extension, and realize stackless IO processing in Java.
async Task<int> AccessTheWebAsync(){
HttpClient client= new HttpClient();
var urlContents= await client.GetStringAsync("http://msdn.microsoft.com");
  return urlContents.Length;
}
   ↓
//LikeWebApplicationTester.java
BlockingQueue<Integer> AccessTheWebAsync() {
HttpClient client = new HttpClient();
return awaiter.await(
() -> client.GetStringAsync("http://msdn.microsoft.com"),
urlContents -> {
return urlContents.length();
});
}
public void doget(){
BlockingQueue<Integer> lengthQueue=AccessTheWebAsync();
awaiter.awaitVoid(()->lengthQueue.take(),
length->{
System.out.println("Length:"+length);
}
);
}
There is an "equivalent" of await developed by EA: https://github.com/electronicarts/ea-async. Refer to the Java example code:
import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;
public class Store
{
public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
{
if(!await(bank.decrement(cost))) {
return completedFuture(false);
}
await(inventory.giveItem(itemTypeId));
return completedFuture(true);
}
}
Java has unfortunately no equivalent of async/await. The closest you can get is probably with ListenableFuture from Guava and listener chaining, but it would be still very cumbersome to write for cases involving multiple asynchronous calls, as the nesting level would very quickly grow.
If you're ok with using a different language on top of JVM, fortunately there is async/await in Scala which is a direct C# async/await equivalent with an almost identical syntax and semantics:
https://github.com/scala/async/
Note that although this functionality needed a pretty advanced compiler support in C#, in Scala it could be added as a library thanks to a very powerful macro system in Scala and therefore can be added even to older versions of Scala like 2.10. Additionally Scala is class-compatible with Java, so you can write the async code in Scala and then call it from Java.
There is also another similar project called Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html which uses different wording but conceptually is very similar, however implemented using delimited continuations, not macros (so it works with even older Scala versions like 2.9).
If you're just after clean code which simulates the same effect as async/await in java and don't mind blocking the thread it is called on until it is finished, such as in a test, you could use something like this code:
interface Async {
void run(Runnable handler);
}
static void await(Async async) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
async.run(new Runnable() {
#Override
public void run() {
countDownLatch.countDown();
}
});
countDownLatch.await(YOUR_TIMEOUT_VALUE_IN_SECONDS, TimeUnit.SECONDS);
}
await(new Async() {
#Override
public void run(final Runnable handler) {
yourAsyncMethod(new CompletionHandler() {
#Override
public void completion() {
handler.run();
}
});
}
});
I have developed a library JAsync to do this.
It is just released today.
It makes the developer's asynchronous programming experience as close as possible to the usual synchronous programming, including code style and debugging.
Here is the example.
#RestController
#RequestMapping("/employees")
public class MyRestController {
#Inject
private EmployeeRepository employeeRepository;
#Inject
private SalaryRepository salaryRepository;
// The standard JAsync async method must be annotated with the Async annotation, and return a Promise object.
#Async()
private Promise<Double> _getEmployeeTotalSalaryByDepartment(String department) {
double money = 0.0;
// A Mono object can be transformed to the Promise object. So we get a Mono object first.
Mono<List<Employee>> empsMono = employeeRepository.findEmployeeByDepartment(department);
// Transformed the Mono object to the Promise object.
Promise<List<Employee>> empsPromise = JAsync.from(empsMono);
// Use await just like es and c# to get the value of the Promise without blocking the current thread.
for (Employee employee : empsPromise.await()) {
// The method findSalaryByEmployee also return a Mono object. We transform it to the Promise just like above. And then await to get the result.
Salary salary = JAsync.from(salaryRepository.findSalaryByEmployee(employee.id)).await();
money += salary.total;
}
// The async method must return a Promise object, so we use just method to wrap the result to a Promise.
return JAsync.just(money);
}
// This is a normal webflux method.
#GetMapping("/{department}/salary")
public Mono<Double> getEmployeeTotalSalaryByDepartment(#PathVariable String department) {
// Use unwrap method to transform the Promise object back to the Mono object.
return _getEmployeeTotalSalaryByDepartment(department).unwrap(Mono.class);
}
}
And in debug mode, you can see all the variable just like the synchronous code.
The other great thing about this project is that it's one of the few projects of its kind that's still active right now. It's just been released, so it has a lot of potential

Categories

Resources