Home > Enterprise >  Calling random code / OTP from different class - ASP.NET Web API
Calling random code / OTP from different class - ASP.NET Web API

Time:11-05

This is my first time posting, apologize for the question format, I'm not sure how to edit it.

My question is, is it possible to call a data generated (in this case the random code for OTP) in different class, in this case from otp controller class to the email service class?

I'm generating an otp to be sent to email with ASP.NET Web API. So far, I created a separate class / controller to generate and save the otp, then another class to set up the email service then lastly email controller to send the email.

I'm generating a random code as OTP to be send directly to the database with the post method.

Here's the code in OTP controller

[HttpPost]
public async Task<IActionResult> AddOTPs(Otp otp)
{
    Random rand = new Random();
    randomcode = (rand.Next(9999999)).ToString();

    var otps = new Otp()
        {
            AlamatEmail = otp.AlamatEmail,
            NamaKaryawan = otp.NamaKaryawan,
            OTP_C = randomcode,
        };

    await _context.Otps.AddAsync(otps);
    await _context.SaveChangesAsync();

    return Ok(otps);
}

enter image description here

In a different class, I have set up the email service to be called in email controller. Here's that code:

public void SendEmail(Otp request)
{
    var email = new MimeMessage();
    email.From.Add(MailboxAddress.Parse(_config.GetSection("EmailUsername").Value));
    email.To.Add(MailboxAddress.Parse(request.AlamatEmail));
    email.Subject = "OTP Test";
    email.Body = new TextPart(TextFormat.Html) { 
            Text = request.OTP_C
        };

    using var smtp = new SmtpClient();
    smtp.Connect(_config.GetSection("EmailHost").Value, 587, SecureSocketOptions.StartTls);
    smtp.Authenticate(_config.GetSection("EmailUsername").Value, _config.GetSection("EmailPassword").Value);

    smtp.Send(email);
    smtp.Disconnect(true);
}

enter image description here

Email controller code :

[HttpPost]
public IActionResult SendEmail(Otp request)
{
    _emailService.SendEmail(request);
    return Ok();
}

Now, all of this code works well without any error, but when I have to call separate API to post the otp to the database, and then another API to send the email where I have to input both the email address and otp manually. So now the flow is like this, post otp to database api, get otp from database api, then post send email api, with total of 3 api calls.

My question is: how can I make sure the random code generated in OTP controller is being sent to the email service class? Or how can I make it so when the otp generated its going to be saved to database and then send the email.

Basically I want to make sure there's only 1-2 APIs being called instead of 3 by eliminating the get otp from database API.

Thank you in advance.

All the code is written in C# for the ASP.NET framework

CodePudding user response:

You cannot do it like this. It would be better if you have a Facade Class after the controller. You can call the Facade class, this class will Save the OTP into the database after that will call the email service with the same OTP. Then this Facade class can be called from the controller.

public class OTPFacede{ 
private readonly EmailService _emailService;
private readonly DBContext _context;
public OTPFacede(EmailSevice emailservice,DBContext context){ 
         _emailService = emailService;
         _context = context;
}
public void SaveAndSendOtp(){
        Random rand = new Random();
        randomcode = (rand.Next(9999999)).ToString();
        var otps = new Otp()
        {
            AlamatEmail = otp.AlamatEmail,
            NamaKaryawan = otp.NamaKaryawan,
            OTP_C = randomcode,
        };
        _context.Otps.AddAsync(otps);
        _context.SaveChanges();
         SendEmail(otps)
   }

public void  SendEmail(Otp request){

       
        var email = new MimeMessage();
        email.From.Add(MailboxAddress.Parse(_config.GetSection("EmailUsername").Value));
        email.To.Add(MailboxAddress.Parse(request.AlamatEmail));
        email.Subject = "OTP Test";
        email.Body = new TextPart(TextFormat.Html) { 
            Text = request.OTP_C
        };


        using var smtp = new SmtpClient();
        smtp.Connect(_config.GetSection("EmailHost").Value, 587, SecureSocketOptions.StartTls);
        smtp.Authenticate(_config.GetSection("EmailUsername").Value, _config.GetSection("EmailPassword").Value);
        smtp.Send(email);
        smtp.Disconnect(true);
    }

}

CodePudding user response:

This isn't an answer to your question, it's a response to your query in the comments (about some sample code for a cryptographically strong random password)

Here's the code:

public static string GetRandomString(int entropyByteCount)
{
    using (var rng = RandomNumberGenerator.Create())
    {
        var byteArray = new byte[entropyByteCount * 8];
        rng.GetBytes(byteArray);
        return BytesToHexString(byteArray);
    }       
}

private static string BytesToHexString(byte[] bytes)
{
    var buffer = new StringBuilder(bytes.Length * 2);
    foreach (var b in bytes)
    {
        buffer.Append(b.ToString("X2"));
    }
    return buffer.ToString();
}

The result will be a hex string that has 16 times as many characters as the value of entropyByteCount parameter. This is because the number of bytes in the array passed to GetBytes should really be divisible by 8 and it takes two hex digits to render the contents of a byte.

The code expects that you have this (using System.Security.Cryptography;) in your program.

There are better ways to convert a byte array to a hex string, take a look at: How do you convert a byte array to a hexadecimal string, and vice versa?

  • Related