Before reading this article, I suggest you download the source code first.
What's Redis
Similar to memcached, Redis is a in-memory database. Apart from this, Redis also allows you to save your data to a hard drive, which makes Redis not only a cache but also a NoSQL database.
Building the web
First, create an ASP.NET MVC project in Visual Studio with no authentication.
Then add a class to store the URL data in Models folder
public class MicroUrlItem
{
[Display(Name = "Shorten URL")]
public string ShortenUrl { get; set; }
[Required]
[Display(Name = "Origin URL")]
[Url]
public string OrignUrl { get; set; }
[Range(1, double.MaxValue)]
[Display(Name = "Expire in Days")]
public int ExpireInDays { get; set; }
[Display(Name = "Expire Mode")]
public ExpireMode ExpireMode { get; set; }
}
ExpireMode is a custom enum so we need to declarate it.
public enum ExpireMode
{
[Display(Name = "By Created")]
ByCreated = 0,
[Display(Name = "By Last Accessed")]
ByLastAccessed = 1,
[Display(Name = "Never")]
Never = 2
}
After that, add a Home page
@model MicroUrl.Models.MicroUrlItem
@{
ViewBag.Title = "Home Page";
}
<h3>Get you micro URL here</h3>
<div class="row">
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { role = "form", @class = "col-lg-6" }))
{
<div class="form-group">
@Html.LabelFor(m => m.OrignUrl)
@Html.TextBoxFor(m => m.OrignUrl, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.OrignUrl, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.ShortenUrl)
@Html.TextBoxFor(m => m.ShortenUrl, new { @class = "form-control", placeHolder = "Keep it empty to generate automatically" })
@Html.ValidationMessageFor(m => m.ShortenUrl, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.ExpireMode)
@Html.EnumDropDownListFor(m => m.ExpireMode, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.ExpireMode, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.ExpireInDays)
@Html.TextBoxFor(m => m.ExpireInDays, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.ExpireInDays, "", new { @class = "text-danger" })
</div>
<button type="submit" class="btn btn-default">Create</button>
}
</div>
and it will look like this
One interesting thing in this code snippet is the EnumDropDownListFor method in HtmlHeper, which in not available until ASP.NET MVC 5.2.
In previous version of ASP.NET MVC, without this method, we had to create the dropdown list items manually, which was a dirty work.
But now we can use this method to generate items from an enum, and use the Display attribute to set its display name.
Then we need a page to tell the user that the operation was succeed in Success.cshtml, that's pretty simple.
@model MicroUrl.Models.MicroUrlItem
@{
ViewBag.Title = "Success";
}
<h2>Success</h2>
<h3>
@{
var url = string.Format("http://{0}:{1}/{2}", Request.Url.Host, Request.Url.Port, Model.ShortenUrl);
}
Your Micro URL is <a href="@url">@url</a>
</h3>
Saving objects to Redis
With those preparations above, we can now start writing code to store data in Redis.
First a Nuget package called ServiceStack.Redis is needed. We can simply search for redis in Package Manager, or install in Console using this following command:
PM> Install-Package ServiceStack.Redis
BTW, you can install ServiceStack.Redis.Signed if a reference to a signed assembly, which has a strong name, is required.
Then we can create a redis client with a using statement, and get a typed client to deal with MicroUrlItems
using (IRedisClient client = new RedisClient())
{
var typedClient = client.As<MicroUrlItem>();
}
Before saving objects in Redis, we need to mark the ShortenUrl property as the primary key with ServiceStack.DataAnnotations.PrimaryKey attribute, so finally the ShortenUrl property in MicroUrlItem should be
public class MicroUrlItem
{
[ServiceStack.DataAnnotations.PrimaryKey]
[Display(Name = "Shorten URL")]
public string ShortenUrl { get; set; }
}
Another thing we need to do is to generate a random url when the ShortenUrl is not specified.
if (string.IsNullOrWhiteSpace(model.ShortenUrl))
{
string url;
do
{
url = GetRandomUrl(6);
} while (typedClient.GetById(url) != null);
model.ShortenUrl = url;
}
And here is how I generate a random url
private static string randomList = "0123456789abcdefghijklmnopqrstuwxyz";
private static string GetRandomUrl(int length)
{
var sb = new StringBuilder(length);
var random = new Random();
for (int i = 0; i < length; i++)
{
var index = random.Next(0, randomList.Length);
sb.Append(randomList[index]);
}
return sb.ToString();
}
Now the model is ready to be saved to Redis
typedClient.Store(model);
Finally, we need to tell Redis when the object will expire if the expiration is specified user.
if (model.ExpireMode != ExpireMode.Never)
typedClient.ExpireIn(model.ShortenUrl, TimeSpan.FromDays(model.ExpireInDays));
Getting objects from Redis
[Route("{shortenUrl}")]
public ActionResult Index(string shortenUrl)
{
using (IRedisClient client = new RedisClient())
{
var typedClient = client.As<MicroUrlItem>();
var microUrlItem = typedClient.GetById(shortenUrl);
if (microUrlItem != null)
{
if (microUrlItem.ExpireMode == ExpireMode.ByLastAccessed)
typedClient.ExpireIn(microUrlItem.ShortenUrl, TimeSpan.FromDays(microUrlItem.ExpireInDays));
return Redirect(microUrlItem.OrignUrl);
}
}
return HttpNotFound();
}
Now we can create a typed client in the same way above, and return a response with HTTP 302 if a matching record was found. When a shorten url is accessed, wo should renew it when its ExpireMode property is set to ByLastAccessed.
Another important thing is to make the Route attribute work, just simply map the AttributeRoutes to the ASP.NET MVC route system when application starts.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Run the application
Before running this application, we need to start Redis, to get Redis, you can go to http://redis.io/download to download it.
For Windows, start a command prompt and go to the Redis folder, and run
redis-server.exe --maxheap 1gb
and we can also launch a command line client to start a monitor
Then we can start the website in Visual Studio, and create a shorten url.
Here is the custom url
And here is the url generated by the service
After we've got the micro url, we can see what happened in redis in the monitor.
Thanks for reading!