While using a computer for work, you'll certainly have to work with licensed applications. One of the important feature of licensed applications is activating the license with a key, but I believe that if you're a first-time user of the application, grasping the activation process can be difficult to ensure the correct execution of the activation process, software developers need to provide detailed and simplified instructions. With a principle of prioritizing user experience and application security, developers often develop the "Auto-Activation" feature, where a single mouse click on the application link automatically activates it and makes it ready to use.
In this article, I will guide you on how to implement the "Auto-Activation" feature via email for a Windows application. There are certainly many other ways to implement this feature, but I will try to provide the simplest instructions possible so that you can understand how this feature works and apply it to your project.
1. Development environment
For implementing the auto-activation feature via email for a Windows application, I will develop an environment with two main components:
-
- ActivationServer:
- Function: Manage data, send emails, redirect activation links
- Email service: Gmail
- Web Framework: ASP.NET
- Application:
- Function: Perform activation
- Application Framework: Windows Form C#
- ActivationServer:
2. Functional design
Regarding the specific operation of the feature, I will describe it according to the diagram below. Through the Windows operating system allowing you to call commands to open applications via "application protocol" (reference "Registering an Application to a URI Scheme"), we will create an application protocol for our application. Then, we can pass the activation key to the application to activate it as a URI parameter.
Picture 1. Auto activation email sending sequence diagram
Picture 2. Auto activation processing sequence diagram
3. Functional development
On the server side, I will implement the routes as follows:
-
- GET Home/index: Display the email sending form.
- POST Home/SendMail: Generate the activation key and send the email.
- GET Home/AutoRedirect: Perform redirection to the application protocol.
HomeController.cs
using System;
using System.Net;
using System.Net.Mail;
using System.Web.Mvc;
using Utility;
namespace ActivationServer.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View("Index", new ViewDataDictionary { { "message", string.Empty } });
}
[HttpPost]
public ActionResult SendMail(FormCollection form)
{
try
{
string emailAddress = form["email"];
string host = "http://myserver.com";
string mailAddress = "myemail@gmail.com";
string mailPassword = "mypassword";
string mailHost = "smtp.gmail.com";
int maiPort = 587;
string mailSubject = "Auto activation email";
string mailBody = "<h2>Auto Activation Email</h2><a href="{{ActivationLink}}">Click here to active!</a>";
mailBody = mailBody.Replace("{{ActivationLink}}",
$"{host}/Home/AutoRedirect?protocol=appdemo¶m=myactivationkey}");
using (SmtpClient client = new SmtpClient())
{
client.Host = mailHost;
client.Port = maiPort;
client.EnableSsl = true;
client.Credentials = new NetworkCredential(mailAddress, mailPassword);
using (MailMessage message = new MailMessage())
{
message.From = new MailAddress(mailAddress);
message.To.Add(new MailAddress($"{emailAddress}"));
message.Subject = mailSubject;
message.Body = mailBody;
message.IsBodyHtml = true;
client.Send(message);
};
};
return View("Index", new ViewDataDictionary { { "message", "Activation mail has been sent!" } });
}
catch (Exception ex)
{
return View("Error", new ViewDataDictionary { { "message", ex.Message } });
}
}
public ActionResult AutoRedirect(string protocol, string param)
{
return Redirect($"{protocol}://?key={param}");
}
}
}
Index.cshtml
@{
ViewBag.Title = "Home Page";
}
<main>
<section class="row" aria-labelledby="aspnetTitle">
<h1 id="title">Auto Activation Demo</h1>
</section>
<div class="row">
<section class="col-md-4" aria-labelledby="">
<form method="post" action="@Url.Action("SendMail")">
<div class="mb-3">
<label for="txtEmail" class="form-label">Email address</label>
<input type="email" class="form-control" name="email" id="txtEmail" required>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</section>
<section class="row mt-3">
<p id="message">@Model["message"]</p>
</section>
</div>
</main>
On the application side, I will implement 2 forms as follows:
-
- Active: Activation screen
Picture 3. Active Screen
-
- Main: Main screen of the application
Picture 4 . Main Screen
I'll add modifications so that the application can be launched via CLI with a "key" parameter. This is aimed at inserting the activation key into the activation screen upon startup.
Programs.cs
using System.Web;
using Utility;
using AppSetting = ApplicationDemo.Properties.Settings;
namespace ApplicationDemo
{
internal static class Program
{
private static Mutex? mutex = null;
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
const string appName = "ApplicationDemo";
bool createdNew;
mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
MessageBox.Show("Application already running!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
ApplicationConfiguration.Initialize();
Form startForm = new Main();
if (string.IsNullOrWhiteSpace(AppSetting.Default.Key) || !CommonCode.IsValidKey(AppSetting.Default.Key))
{
string[] args = Environment.GetCommandLineArgs();
string key = string.Empty;
if (args.Length > 1)
{
Uri uri = new Uri(args[1]);
key = $"{HttpUtility.ParseQueryString(uri.Query).Get("key")}";
}
startForm = new Active(key);
}
Application.Run(startForm);
}
}
}
Active.cs
using Utility;
using AppSetting = ApplicationDemo.Properties.Settings;
namespace ApplicationDemo
{
public partial class Active : Form
{
public Active(string key)
{
InitializeComponent();
txtActivationKey.Text = key;
}
private void btnActive_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrWhiteSpace(txtActivationKey.Text))
{
throw new Exception("Please enter activation key!");
}
if (CommonCode.IsValidKey(txtActivationKey.Text))
{
MessageBox.Show("Activation Successful", "Information", MessageBoxButtons.OK,
MessageBoxIcon.Information);
AppSetting.Default.Key = txtActivationKey.Text;
AppSetting.Default.Save();
Main main = new();
main.Show();
Hide();
}
else
{
MessageBox.Show("The activation key is invalid!", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void Active_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
private void Active_Shown(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(txtActivationKey.Text))
{
btnActive.PerformClick();
}
}
}
}
Main.cs
using AppSetting = ApplicationDemo.Properties.Settings;
namespace ApplicationDemo
{
public partial class Main : Form
{
public Main()
{
InitializeComponent();
}
private void btnDeactive_Click(object sender, EventArgs e)
{
AppSetting.Default.Key = string.Empty;
AppSetting.Default.Save();
Active active = new Active(string.Empty);
active.Show();
Hide();
}
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
}
}
To make the application operational with an application protocol, we'll register it through the registry as follows, with the "ExecFilePath" is the location where the application is installed.
AppDemo.reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\appdemo]
"URL Protocol"=""
@="URL:appdemo"
[HKEY_CLASSES_ROOT\appdemo\shell]
[HKEY_CLASSES_ROOT\appdemo\shell\open]
[HKEY_CLASSES_ROOT\appdemo\shell\open\command]
@="ExecFilePath" \"%1\""
To perform registry registration during application setup, you'll need to use a third-party software to package the application.
4. Operational demo:
5. Advantages and disadvantages:
-
- Advantages:
- User Experience: Streamlined activation process enhances user experience, reducing user frustration and increasing satisfaction.
- Automation: Automating the activation process saves time and effort for both users and administrators.
- Security: By encrypting the activation key and embedding it in a link, security is enhanced compared to manual entry or transmission via insecure channels.
- Ease of Use: One-click activation simplifies the process for users, especially for those who may not be technically savvy.
- Disadvantages:
- Complexity of Implementation: Setting up the infrastructure for automated activation, including server-side processing and email integration, can be complex and require additional development effort.
- Compatibility Issues: Because the information of the application protocol needs to be registered with the exact path to the application to be opened, it will not work if the user moves the application to a different directory.
- Advantages:
Cover image from freepik.com
Reference: