ASP.NET has been a cornerstone of web development on the Microsoft stack for over two decades. Whether you are maintaining a legacy Web Forms application, working with ASP.NET MVC, or building modern applications with ASP.NET Core, there are fundamental tools and concepts that every developer needs to understand. This guide covers the essential resources, tools, and configuration knowledge that will help you work more effectively with ASP.NET.
Machine Key Generation
The machine key is one of the most important security configuration elements in ASP.NET. It consists of two cryptographic keys stored in web.config or machine.config:
- validationKey — Used to create a message authentication code (MAC) to verify that data (like ViewState) has not been tampered with
- decryptionKey — Used to encrypt and decrypt forms authentication tickets and ViewState (when encryption is enabled)
When You Need a Custom Machine Key
- Web farm deployments — All servers must share the same machine key so that a request handled by one server can decrypt data encrypted by another
- Persistence across app pool recycles — Auto-generated keys change when the application pool restarts, invalidating all existing ViewState, sessions, and auth tickets
- Cross-application authentication — When multiple applications share forms authentication, they need the same machine key
Generating a Machine Key
Using IIS Manager (Recommended for IIS-hosted apps)
- Open IIS Manager
- Select your site or application
- Double-click Machine Key in the Features View
- Uncheck “Automatically generate at runtime” for both validation and decryption keys
- Click Generate Keys in the Actions panel
- Click Apply
Using PowerShell
# Generate cryptographically secure machine keys using PowerShell
function Generate-MachineKey {
param(
[int]$ValidationKeyLength = 64,
[int]$DecryptionKeyLength = 32
)
$rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::new()
$validationKeyBytes = New-Object byte[] $ValidationKeyLength
$rng.GetBytes($validationKeyBytes)
$validationKey = [BitConverter]::ToString($validationKeyBytes) -replace '-', ''
$decryptionKeyBytes = New-Object byte[] $DecryptionKeyLength
$rng.GetBytes($decryptionKeyBytes)
$decryptionKey = [BitConverter]::ToString($decryptionKeyBytes) -replace '-', ''
$rng.Dispose()
return @{
ValidationKey = $validationKey
DecryptionKey = $decryptionKey
}
}
$keys = Generate-MachineKey
Write-Host "Validation Key: $($keys.ValidationKey)"
Write-Host "Decryption Key: $($keys.DecryptionKey)"
Configuring in web.config
<system.web>
<machineKey
validationKey="YOUR_GENERATED_VALIDATION_KEY"
decryptionKey="YOUR_GENERATED_DECRYPTION_KEY"
validation="HMACSHA256"
decryption="AES" />
</system.web>
Segurança note: Never use machine keys found in blog posts, Stack Overflow answers, or documentation examples. Always generate your own unique keys.
ViewState Management
ViewState is a mechanism in ASP.NET Web Forms that persists control state between postbacks by storing serialized data in a hidden field (__VIEWSTATE) in the HTML page.
How ViewState Works
- Before the page is rendered, ASP.NET serializes the state of all controls into a Base64-encoded string
- This string is embedded in the page as a hidden form field
- On postback, ASP.NET deserializes the string to restore control state before event processing
- The machine key validates (and optionally encrypts) this data to prevent tampering
Controlling ViewState Size
Large ViewState can significantly impact page performance because the entire string is sent to the client and back with every postback.
<%-- Disable ViewState for controls that don't need it --%>
<asp:GridView ID="gvReport" runat="server" EnableViewState="false" />
<%-- Disable ViewState at the page level --%>
<%@ Page EnableViewState="false" %>
<!-- Disable ViewState application-wide in web.config -->
<system.web>
<pages enableViewState="false" />
</system.web>
ViewState Melhores Práticas
| Practice | Reason |
|---|---|
| Disable on read-only controls | GridViews, Labels, and Literals displaying data that is reloaded from the database on every request do not need ViewState |
| Use ControlState for critical data | ControlState cannot be disabled by the developer and is appropriate for data a control absolutely needs to function |
| Enable ViewState MAC validation | Always keep enableViewStateMac="true" (the default); disabling it creates a serious security vulnerability |
| Monitor ViewState size | Use page tracing to see the ViewState size per control and identify the largest offenders |
| Consider compression | For pages with large unavoidable ViewState, implement custom compression using GZipStream in the page lifecycle |
Decoding ViewState for Debugging
You can inspect ViewState contents for debugging purposes:
// Add this to your page to decode ViewState during development
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (IsPostBack)
{
// The ViewState is available as a StateBag
foreach (string key in ViewState.Keys)
{
System.Diagnostics.Debug.WriteLine(
$"ViewState[{key}] = {ViewState[key]}");
}
}
}
Session State Configuração
Session state allows you to store user-specific data on the server between requests. ASP.NET supports multiple session state modes, each with different trade-offs.
Session State Modes
InProc (In-Process)
<system.web>
<sessionState mode="InProc" timeout="20" />
</system.web>
- Pros: Fastest performance; no serialization required; objects stored as live references
- Cons: Lost on app pool recycle; not shareable across servers; consumes web server memory
- Best for: Single-server development/testing, applications where session loss is acceptable
StateServer
<system.web>
<sessionState mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
timeout="20" />
</system.web>
- Pros: Survives app pool recycles; can be shared across servers if pointed to same state server
- Cons: Requires objects to be serializable; slower than InProc; single point of failure
- Best for: Small web farms, applications that need session persistence across recycles
To start the ASP.NET State Service:
# Start the ASP.NET State Service
net start aspnet_state
# Set it to start automatically
sc config aspnet_state start= auto
SQL Server
<system.web>
<sessionState mode="SQLServer"
sqlConnectionString="Data Source=SQLSERVER;Integrated Security=true"
timeout="20" />
</system.web>
- Pros: Persistent and durable; shareable across web farm; survives both app pool and server restarts
- Cons: Slowest option; requires SQL Server infrastructure; all objects must be serializable
- Best for: Production web farms, applications requiring high availability
Set up the session state database:
# Create the session state database using aspnet_regsql
aspnet_regsql.exe -S SQLSERVER -E -ssadd -sstype p
Session State Comparison
| Feature | InProc | StateServer | SQL Server |
|---|---|---|---|
| Speed | Fastest | Moderate | Slowest |
| Serialization Required | No | Yes | Yes |
| Survives App Pool Recycle | No | Yes | Yes |
| Survives Server Restart | No | No | Yes |
| Web Farm Support | No | Yes | Yes |
| Setup Complexity | None | Low | Moderate |
ASP.NET Debugging Tools
Built-in Tracing
ASP.NET includes a powerful tracing feature that shows the full page lifecycle, control tree, session contents, and ViewState sizes.
<%-- Enable tracing for a single page --%>
<%@ Page Trace="true" TraceMode="SortByTime" %>
<!-- Enable tracing application-wide in web.config -->
<system.web>
<trace enabled="true" pageOutput="false"
requestLimit="50" localOnly="true"
mostRecent="true" />
</system.web>
When pageOutput is false, trace output is available at ~/Trace.axd instead of being appended to each page.
Debugging with Visual Studio
Key debugging features for ASP.NET:
- Breakpoints with conditions — Right-click a breakpoint and set a condition to break only when a specific variable value or hit count is reached
- Immediate Window — Evaluate expressions and call methods while paused at a breakpoint
- Diagnostic Tools — Monitor memory usage, CPU, and events in real-time during debugging
- IntelliTrace — Record and replay application execution (Enterprise edition)
<!-- Enable detailed error messages during development -->
<system.web>
<compilation debug="true" targetFramework="4.8" />
<customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/NotFound.aspx" />
<error statusCode="500" redirect="~/ServerError.aspx" />
</customErrors>
</system.web>
Logging with ELMAH
ELMAH (Error Logging Modules and Handlers) is a widely-used library for automatic error logging in ASP.NET:
# Install ELMAH via NuGet
Install-Package Elmah
<!-- ELMAH configuration in web.config -->
<configSections>
<sectionGroup name="elmah">
<section name="security" requirePermission="false"
type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false"
type="Elmah.ErrorLogSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<elmah>
<security allowRemoteAccess="false" />
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="ElmahDb" />
</elmah>
Access the error log at ~/elmah.axd.
Configuração Melhores Práticas
web.config Segurança Essentials
<system.web>
<!-- Never leave debug="true" in production -->
<compilation debug="false" targetFramework="4.8" />
<!-- Always show custom errors to remote users -->
<customErrors mode="RemoteOnly" />
<!-- Require SSL for authentication cookies -->
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="30"
requireSSL="true" protection="All"
slidingExpiration="true" />
</authentication>
<!-- Set secure HTTP headers -->
<httpRuntime targetFramework="4.8"
enableVersionHeader="false"
maxRequestLength="4096" />
</system.web>
<system.webServer>
<!-- Remove server identification headers -->
<security>
<requestFiltering removeServerHeader="true" />
</security>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="X-XSS-Protection" value="1; mode=block" />
</customHeaders>
</httpProtocol>
</system.webServer>
Configuração Transforms
Use web.config transforms to manage environment-specific settings:
<!-- Web.Release.config -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<customErrors mode="On" xdt:Transform="SetAttributes(mode)" />
</system.web>
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=PROD-SQL;..."
xdt:Transform="SetAttributes"
xdt:Locator="Match(name)" />
</connectionStrings>
</configuration>
Connection String Management
<!-- Store connection strings in their own section -->
<connectionStrings>
<clear />
<add name="DefaultConnection"
connectionString="Data Source=.;Initial Catalog=MyApp;Integrated Security=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
For sensitive connection strings, encrypt the section:
# Encrypt the connectionStrings section
aspnet_regiis -pe "connectionStrings" -app "/MyApplication"
# Decrypt (for editing)
aspnet_regiis -pd "connectionStrings" -app "/MyApplication"
Modern ASP.NET Core Equivalents
If you are migrating to ASP.NET Core, here is how these concepts map:
| ASP.NET Framework | ASP.NET Core |
|---|---|
| Machine Key in web.config | Data Protection API (Microsoft.AspNetCore.DataProtection) |
| ViewState | Not applicable (no Web Forms); use TempData, client-side state, or session |
| Session State in web.config | services.AddSession() with IDistributedCache |
| ELMAH | Serilog, NLog, or built-in ILogger with Application Insights |
| web.config transforms | appsettings.{Environment}.json files |
| Forms Authentication | ASP.NET Core Identity or cookie authentication middleware |
// ASP.NET Core session configuration in Program.cs
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(20);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
// In the middleware pipeline
app.UseSession();
Resumo
Understanding these core ASP.NET tools and configurations is essential whether you are maintaining existing applications or building new ones. Machine keys protect your application’s encrypted data, ViewState management keeps your pages performant, proper session state configuration ensures scalability, and solid debugging practices help you resolve issues quickly. Always follow security best practices in your configuration, and consider the migration path to ASP.NET Core for new projects.