Introduction
There may be times when business requirements require query parameters not to be shown for specific pages or all pages in the application. Two ways to hide query parameters are provided, which exclude a third option using temp data, where the following project demonstrates how to hide query parameter values.
ASP.NET Core project Source code
💡Data used for both examples
Is read from appsettings.json in section Programs. This is done so that the reader need not be hassled with setting up a database.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Programs": {
"YogaPostures": "Yoga Postures",
"PayneMeditation": "Kriya and Meditation",
"RestorativeYoga": "Restorative Yoga"
}
}
And configured in Program.cs
builder.Services.Configure<Dictionary<string, string>>
(builder.Configuration.GetSection("Programs"));
HttpContext Class
Session state is accessed from a Razor Pages PageModel class or MVC Controller class with HttpContext.Session. This property is an ISession implementation.
Note
Don't store sensitive data in session state. The user might not close the browser and clear the session cookie. Some browsers maintain valid session cookies across browser windows. A session might not be restricted to a single user. The next user might continue to browse the app with the same session cookie.
Set and get Session values
First, there are two things to add to Program.cs (can be found in the provided source code).
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSession(o =>
{
o.Cookie.HttpOnly = true;
o.Cookie.IsEssential = true;
o.IdleTimeout = TimeSpan.FromMinutes(20);
});
. . .
app.UseStaticFiles();
app.UseSession(); // <-- important
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
}
}
Example
A user selects an item from a dropdown, followed by selecting a number in the calling page, which is passed to another page (the target page).
Caller page front-end
@page
@model MultipleSubmitButtons1.Pages.Index1Model
@{
ViewData["Title"] = "Session two params";
}
<script src="lib/debugHelper.js"></script>
<link href="~/css/indexpage.css" rel="stylesheet" />
<div class="container">
<form method="post">
@Html.AntiForgeryToken()
<div class="mb-3">
<label asp-for="Program" class="form-label">Program</label>
<select asp-for="Program" class="form-select w-25">
@foreach (var kvp in Model.Programs)
{
<!-- Key is the actual identifier stored in Program -->
<option value="@kvp.Key">@kvp.Value</option>
}
</select>
<span asp-validation-for="Program" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Count" class="form-label">Count</label>
<input asp-for="Count"
type="number"
class="form-control input-small-number d-inline-block text-end"
style="width: 6rem;"
min="1"/>
<span asp-validation-for="Count" class="text-danger"></span>
</div>
<button type="submit" asp-page-handler="Button1" class="btn btn-primary">Submit</button>
</form>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Caller backend code
public class Index1Model(IOptions<Dictionary<string, string>> programs) : PageModel
{
public Dictionary<string, string> Programs { get; } = programs.Value;
// Bind the posted fields
[BindProperty]
public string? Program { get; set; }
[BindProperty]
[Range(1, int.MaxValue, ErrorMessage = "Count must be at least 1.")]
public int Count { get; set; }
public IActionResult OnPostButton1()
{
if (!ModelState.IsValid)
{
return Page();
}
// Key is what got posted from the <select>
var selectedKey = Program;
// Lookup the value (friendly display text) from Programs dictionary
Programs.TryGetValue(selectedKey!, out var selectedValue);
Console.WriteLine(Program);
HttpContext.Session.SetString("Program", selectedValue!);
HttpContext.Session.SetInt32("Count", Count);
return RedirectToPage("Index2");
}
}
- HttpContext.Session.SetString("Program", selectedValue!); assigns the select text to Program which will be read in the target page.
- HttpContext.Session.SetInt32("Count", Count); assigns the count to Count which will be read in the target page.
Target page
In the target page, GetString and GetInt32 retrieve values from the calling page.
Backend code
public class Index2Model : PageModel
{
public string ProgramParam { get; private set; }
public int? CountParam { get; private set; }
public void OnGet()
{
ProgramParam = HttpContext.Session.GetString("Program");
CountParam = HttpContext.Session.GetInt32("Count");
}
}
Front-end code
<h1 class="fs-4 text-center">Passed via Session</h1>
<div class="container">
<div class="row mb-2">
<div class="col-2 text-end">
First value:
</div>
<div class="col-8 fw-bold">
@Model.ProgramParam
</div>
</div>
<div class="row mb-2">
<div class="col-2 text-end">
Second value:
</div>
<div class="col-8 fw-bold">
@(Model.CountParam.HasValue ? Model.CountParam.Value.ToString() : "N/A")
</div>
</div>
</div>
Example 2 all on one page
In this example,OnPost gets the action and value from the select button click along with the numeric input.
Backend code
public class IndexModel(IOptions<Dictionary<string, string>> programs) : PageModel
{
[BindProperty]
[Range(1, int.MaxValue, ErrorMessage = "Enter at least 1.")]
public int CountInput { get; set; }
public int? MainCount { get; private set; }
public string? Program { get; private set; }
public Dictionary<string, string> Programs { get; } = programs.Value;
public void OnGet()
{
}
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
if (!Request.Form.TryGetValue("action", out var actionValue) || actionValue.Count == 0 || actionValue[0] is null)
{
ModelState.AddModelError(string.Empty, "Action is required.");
MainCount = null;
return Page();
}
MainCount = CountInput;
var actionKey = actionValue[0]!;
if (Programs.TryGetValue(actionKey, out var programName))
{
Program = programName;
}
else
{
ModelState.AddModelError(string.Empty, "Unknown action.");
MainCount = null;
}
return Page();
}
}
Front-end code
<link href="~/css/indexpage.css" rel="stylesheet" />
<h1 class="mb-3 fs-4">Select Your Program</h1>
<form method="post" class="vstack gap-3">
<!-- Show any page-level model errors -->
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="mb-3 d-flex align-items-center gap-2">
<label asp-for="CountInput" class="form-label mb-0">How many sessions?</label>
<!-- see indexPage.css for styling -->
<input asp-for="CountInput"
type="number" min="1"
class="form-control input-small-number d-inline-block text-end"
style="width: 6rem;"/>
<!-- Field-level message goes right under/next to the input -->
<span asp-validation-for="CountInput" class="text-danger ms-2"></span>
</div>
<div class="d-flex flex-wrap gap-2">
@* create buttons for each program from json in appsettings.json *@
@foreach (var program in Model.Programs)
{
<button type="submit"
name="action"
value="@program.Key"
class="btn btn-outline-dark">
@program.Value
</button>
}
</div>
@* display result from form submission *@
@if (Model.MainCount.HasValue && !string.IsNullOrEmpty(Model.Program))
{
<div class="alert alert-success mt-3">
You requested <strong>@Model.MainCount</strong> session(s) of <strong>@Model.Program</strong>.
</div>
}
</form>
@section Scripts {
<!-- This pulls in jquery, jquery.validate, jquery.validate.unobtrusive -->
<partial name="_ValidationScriptsPartial" />
}
Summary
Presented are three common techniques to hide query parameter values. Before using one, make sure to understand the code flow.
Top comments (0)