Replies: 6 comments
-
OK, I think I've got the hang of this. Maybe someone who understands this library better than me (ie pretty much anyone reading!) could take a look and see if I'm doing this right... Suppose I have an async method that may throw an exception, for example... async Task<int> Divide(int n, int d) =>
await Task.Run(() => n / d); (I know this is a silly example, but I wanted to keep it simple) I can then use TryAsync<int> DivideTa(int n, int d) =>
TryAsync(() => Divide(n, d))
.Map(r => r); ...and call it as follows... DivideTa(4, 0)
.Match(r => Console.WriteLine(r), ex => Console.WriteLine(ex.Message)); If the async method is fairly simple (as in this case), I can insert it directly in the TryAsync<int> DivideTa(int n, int d) =>
TryAsync(() => Task.Run(() => n / d))
.Map(r => r); This can be called as before. If the method to be called doesn't return anything if all went well (say it sends an email, where you're only interested if anything went wrong), then you can use TryAsync<Unit> DoSomething(int n) =>
TryAsync(() => {
// Do whatever might thrown an exception. I our case, mock this with a simple check...
if (n > 10) {
throw new ArgumentException("Can't handle numbers bigger than 10");
}
return Task.Run(() => new Unit());
})
.Map(x => x); ...which can be called as follows... DoSomething(1)
.Match(_ => Console.WriteLine("All worked"), ex => Console.WriteLine(ex.Message)); Is this correct? Any comments? |
Beta Was this translation helpful? Give feedback.
-
public TryAsync<string> SendEmail(MailMessage msg) =>
from result in TryAsync(() => emailService.SendEmail(msg))
select "OK"; |
Beta Was this translation helpful? Give feedback.
-
@louthy Thanks for that. Useful to see the fluent version. Please could you take a quick look at my follow-up post, and check I got it right for the case where you don't need a return value? Thanks again. |
Beta Was this translation helpful? Give feedback.
-
OK, assuming my code was right, I have a major problem. The previous version of the email service method looked like this... public async Task<string> SendEmailFromUserOld(MimeMessage msg, User user) {
string res = "Start";
try {
using SmtpClient client = new();
res = "Connecting";
await client.ConnectAsync(_gmailSettings.SmtpServer, _gmailSettings.SmtpPort, false);
res = "Connected";
await client.AuthenticateAsync(user.GmailAddress, user.GmailPassword);
res = "Authed";
await client.SendAsync(msg);
res = "Sent";
await client.DisconnectAsync(true);
return "Done";
}
catch (Exception ex) {
return $"{res}: {ex.Message}";
}
} When I called it like this... string msg = await EmailService.SendEmailFromUserOld(msg, user); ...I got "Done" as the return value, and the email was sent. I did a new version of the method using public TryAsync<Unit> SendEmailFromUser(MimeMessage msg, User user) =>
TryAsync(() => {
using SmtpClient client = new();
client.ConnectAsync(_gmailSettings.SmtpServer, _gmailSettings.SmtpPort, false);
client.AuthenticateAsync(user.GmailAddress, user.GmailPassword);
client.SendAsync(msg);
client.DisconnectAsync(true);
return Task.Run(() => new Unit());
})
.Map(x => x); ...and call it as follows... await EmailService.SendEmailFromUser(msg, user)
.Match(_ => {
string msg = "Email sent";
},
ex => {
string msg = ex.Message;
}); The success action is always called, but the email doesn't seem to be sent. I have stepped through the code in the email service method, and it doesn't throw any exceptions (which I wouldn't expect it to, as it's a carbon copy of the original code with the Any ideas? I realise that this isn't strictly an issue with the library, but it only happens when I use the Any ideas? Thanks again. |
Beta Was this translation helpful? Give feedback.
-
If you're wrapping up a task you need to use the async/await machinery: public TryAsync<Unit> SendEmailFromUser(MimeMessage msg, User user) =>
TryAsync(async () => {
using SmtpClient client = new();
await client.ConnectAsync(_gmailSettings.SmtpServer, _gmailSettings.SmtpPort, false);
await client.AuthenticateAsync(user.GmailAddress, user.GmailPassword);
await client.SendAsync(msg);
await client.DisconnectAsync(true);
return unit;
}); Or, you can wrap the individual calls: public static class Smtp
{
public static TryAsync<A> Use<A>(Func<SmtpClient, TryAsync<A>> ma) =>
async () =>
{
using var client = new SmtpClient();
return await ma(client).Try();
};
public static TryAsync<Unit> Connect(SmtpClient client, string server, int port) =>
TryAsync(async () => { await client.ConnectAsync(server, port, false); return unit; });
public static TryAsync<Unit> Auth(SmtpClient client, string address, string pass) =>
TryAsync(async () => { await client.AuthenticateAsync(address, pass); return unit; });
public static TryAsync<Unit> Send(SmtpClient client, string msg) =>
TryAsync(async () => { await client.SendAsync(msg); return unit; });
public static TryAsync<Unit> Disconnect(SmtpClient client) =>
TryAsync(async () => { await client.DisconnectAsync(); return unit; });
} And then use LINQ: public TryAsync<Unit> SendEmailFromUser(MimeMessage msg, User user) =>
Smtp.Use(client =>
from _1 in Smtp.Connect(client, _gmailSettings.SmtpServer, _gmailSettings.SmtpPort)
from _2 in Smtp.Auth(client, user.GmailAddress, user.GmailPassword)
from _3 in Smtp.Send(client, msg)
from _4 in Smtp.Disconnect(client)
select unit); |
Beta Was this translation helpful? Give feedback.
-
@louthy Thanks, it was the last line of the method that got me. When I tried using All working now, thanks very much again. |
Beta Was this translation helpful? Give feedback.
-
Sorry if this is a dumb question, but I can't seem to work this out.
I have a method (simplified for clarity)...
Now obviously, this can be improved, as merely returning a string isn't really the best way to do it. As far as I can see,
TryAsync
was designed for this type of issue, but I'm stuck trying to work out how to use it.Please could someone show me how I would change this method, and how I would call it in a more functional way?
Thanks
Beta Was this translation helpful? Give feedback.
All reactions