TOC
HttpContext:

Cookies

HTTP, the protocol that takes care of the communication between a server and a client on the web, is known as a stateless protocol. In other words, if a user requests two pages on a server, no information will be shared between these two requests automatically. Instead, a developer will have to rely on something called cookies (or sessions - more on those later) to share information between the requests. This is extremely useful in a lot of situations, e.g. to keep a user logged in between several requests etc.

Pretty much all server-side technologies have built-in support for handling cookies and of course the ASP.NET MVC framework does as well. In fact, dealing with cookies is pretty easy, thanks to the functionality found on the HttpContext class. In this article, you'll learn how to set a cookie and then read it again afterwards, so that you will be able to share information about a specific visitor between his/hers requests.

What is a cookie?

A cookie is basically a physical, plain-text file stored by the client (usually a browser), tied to a specific website. The client will then allow this specific website to read the information stored in this file on subsequent requests, basically allowing the server (or even the client itself) to store information for later use.

Setting and reading cookies

Setting a cookie, and reading it again later on, with ASP.NET MVC is very, very easy. Here's how you can send a cookie to the client, in its most basic form:

HttpContext.Response.Cookies.Append("user_id", "1");

Notice how I use the Response property on the HttpContext class, where I can access the Cookies property. Using the Append() method, I can add a Cookie to the output, by supplying a name and a value for it. The name (user_id) is what we'll use later on to get the value (1) back. And getting the actual value back is just as easy:

var userId = HttpContext.Request.Cookies["user_id"];

Notice how I now use the Request property instead of the Response, when reading the value back - the reason is that setting a cookie is done by adding information to the response sent to the client, while reading it means that you are pulling information from the request made by the client (a normal browser will automatically send all relevant cookies with each request).

So, now that you know how to write and read cookie information, let's combine that into a very simple example, where we add a piece of information as a cookie if it's not already present - this will be a great way to know if a user has visited the page before or not:

public class CookiesController : Controller
{
    public IActionResult Index()
    {
if(!HttpContext.Request.Cookies.ContainsKey("first_request"))
{
    HttpContext.Response.Cookies.Append("first_request", DateTime.Now.ToString());
    return Content("Welcome, new visitor!");
}
else
{
    DateTime firstRequest = DateTime.Parse(HttpContext.Request.Cookies["first_request"]);
    return Content("Welcome back, user! You first visited us on: " + firstRequest.ToString());
}
    }
}

Our Controller action now produces response based on whether the visitor has visited the page before, by always checking for the presence of a cookie with the name of "first_request" - if this cookie is not present, we add it, while setting the value to the current date and time. If the cookie is present, we can assume that the visitor has visited the page before and we can even tell the visitor when the first visit occurred.

So, this is basic cookies in a nutshell and now you know how to write and read them. But there's a bit more you need to know, if you want to take full advantage of cookies.

CookieOptions

As an optional third parameter to the Append() method we just used, you can pass an instance of the CookieOptions class. It allows you to adjust several important aspects of your cookie, e.g. how long it should stay alive and stuff like domain(s) and path. Allow me to go through the most important properties, but first, make sure that you have included the Microsoft.AspNetCore.Http namespace, where the CookieOptions class lives:

using Microsoft.AspNetCore.Http;

Now you can create an instance of the CookieOptions class, which will use the default settings, and then pass it to the Append() method:

CookieOptions cookieOptions = new CookieOptions();            
HttpContext.Response.Cookies.Append("first_request", DateTime.Now.ToString(), cookieOptions);

Before passing it though (so, between the two lines of code), you likely want to change some of the options. Here are the most relevant ones:

CookieOptions.Expires

By default, your cookie will be a so-called session cookie, meaning that it will only live as long as the browser remains open - once the browser is closed, the cookie is deleted by the browser. However, you are free to change this behavior using the Expires property. This property is a DateTimeOffset instance, which makes it easy to configure an expiry time, like this:

cookieOptions.Expires = new DateTimeOffset(DateTime.Now.AddDays(7));

This will make the cookie expire in 7 days. You can of course adjust this using the methods like AddDays(), AddHours() and so on.

CookieOptions.Domain

By default, the cookie will be set for the domain which made the request. So, if your page is accessed by the domain mywebsite.com, the cookie will be set for mywebsite.com. If your page is accessed using a subdomain, this subdomain will be used, and this is important, because a subdomain could be "www". So, if your page is accessed by www.mywebsite.com, the cookie will, by default, only be accessible from www.mywebsite.com and NOT mywebsite.com. Therefore, it can be a good idea to set the Domain property to the base-domain of your website, prefixed with a dot, like this:

cookieOptions.Domain = ".mywebsite.com";

Now your cookie will be accessible from mywebsite.com as well as all possible subdomains. On the other hand, if you don't have full control over the domain, you may want to limit the domain of the cookie to the specific (sub)domain you control.

CookieOptions.Path

By default, the Path of the cookie will be set to "/", which basically means that the cookie will be valid for all pages of the website. However, under certain conditions, you may need a cookie that's valid only for a specific page or folder. This is easily accomplished with the Path property:

cookieOptions.Path = "/users/";

With that in place, the cookie will now only be visible and readable to pages in the "users" folder, as well as sub-folders to it.

More properties of CookieOptions

There are several other interesting properties to be found on CookieOptions, like IsEssential, HttpOnly and Secure. If you want to know more about them, I suggest that you have a look at the documentation for CookieOptions.

Summary

Thanks to cookies, you can save information about the visitor and retrieve it again on subsequent requests. This is a very important technique, used in a wide range of situations, like keeping the user logged in, tracking their use of your website and much more.