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

  1. Open IIS Manager
  2. Select your site or application
  3. Double-click Machine Key in the Features View
  4. Uncheck “Automatically generate at runtime” for both validation and decryption keys
  5. Click Generate Keys in the Actions panel
  6. 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

  1. Before the page is rendered, ASP.NET serializes the state of all controls into a Base64-encoded string
  2. This string is embedded in the page as a hidden form field
  3. On postback, ASP.NET deserializes the string to restore control state before event processing
  4. 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

PracticeReason
Disable on read-only controlsGridViews, Labels, and Literals displaying data that is reloaded from the database on every request do not need ViewState
Use ControlState for critical dataControlState cannot be disabled by the developer and is appropriate for data a control absolutely needs to function
Enable ViewState MAC validationAlways keep enableViewStateMac="true" (the default); disabling it creates a serious security vulnerability
Monitor ViewState sizeUse page tracing to see the ViewState size per control and identify the largest offenders
Consider compressionFor 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

FeatureInProcStateServerSQL Server
SpeedFastestModerateSlowest
Serialization RequiredNoYesYes
Survives App Pool RecycleNoYesYes
Survives Server RestartNoNoYes
Web Farm SupportNoYesYes
Setup ComplexityNoneLowModerate

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 FrameworkASP.NET Core
Machine Key in web.configData Protection API (Microsoft.AspNetCore.DataProtection)
ViewStateNot applicable (no Web Forms); use TempData, client-side state, or session
Session State in web.configservices.AddSession() with IDistributedCache
ELMAHSerilog, NLog, or built-in ILogger with Application Insights
web.config transformsappsettings.{Environment}.json files
Forms AuthenticationASP.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.