This repository contains a non-SDK ASP.NET Web Forms sample storefront that targets v2.0 in MSBuild and is intended to run on a machine with .NET Framework 2.0 Service Pack 2 installed. v2.0 is the correct project target moniker; Service Pack 2 is a deployment and runtime prerequisite rather than a separate target framework identifier.
- ASP.NET Web Forms application project in EShop/EShop.csproj
- C# 2.0-compatible code only
- Forms Authentication for sign-in state
- Session-backed shopping cart
- ADO.NET persistence for customers and orders
- SQL Server Express LocalDB connection retained through
EShopDatabasein EShop/Web.config
To build the full web application project as authored, the machine needs all of the following:
- .NET Framework 2.0 reference assemblies for compilation.
- .NET Framework 2.0 Service Pack 2 installed for actual runtime compatibility.
- MSBuild or Visual Studio Build Tools that can load legacy ASP.NET Web Application Projects.
Microsoft.WebApplication.targetsfrom a Visual Studio installation that provides Web Application build targets.- SQL Server Express LocalDB, including
SqlLocalDB.exe, if you want the built-in customer and order persistence to work. - A compatible ASP.NET host that can run Web Forms applications, such as IIS with ASP.NET enabled or a Visual Studio-era development host that can load this project type.
The web project conditionally imports Microsoft.WebApplication.targets from the standard Visual Studio Web Applications locations. If those targets are missing, a C# build may still succeed, but it does not establish that the full web build tooling is available.
The local Windows setup has NetFx3 installed and has successfully built the .NET 2.0 solution with Visual Studio 18 Enterprise MSBuild. The x86 IIS Express host with /clr:v2.0 has also served the homepage and product details successfully. These results do not establish that every application flow has been verified.
This repo intentionally avoids post-.NET 2.0 dependencies. The project references only:
SystemSystem.ConfigurationSystem.DataSystem.WebSystem.Xml
The app must not reference or require:
System.CoreSystem.Web.MvcSystem.LinqSystem.ComponentModel.DataAnnotations- newer framework assemblies introduced after .NET Framework 2.0 for core application behavior
On machines without the full legacy web toolchain, a standalone full-framework compiler can still validate the code-behind and service layer with /langversion:ISO-2, but that does not compile .aspx and .master markup through the real ASP.NET Web Application pipeline.
The configured connection string is kept in EShop/Web.config:
<add name="EShopDatabase" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;Initial Catalog=EShopDatabase;Integrated Security=True;Pooling=False" providerName="System.Data.SqlClient" />The application does not pass the (LocalDB)\MSSQLLocalDB server name directly into .NET 2.0 SqlClient. Instead, EShop/Services/Database.cs runs SqlLocalDB.exe info MSSQLLocalDB, extracts the np: named pipe reported by LocalDB, replaces the data source with that named pipe, and then opens the SQL connection. This adaptation is required because the legacy client stack does not understand modern LocalDB instance syntax directly.
At first successful connection the app:
- Creates the
EShopDatabasedatabase if it does not exist. - Creates the
Customers,Orders, andOrderLinestables if they do not exist. - Applies the order-number column-width fixup expected by this version of the sample.
- Migrates a legacy
App_Data/customers.xmlfile into SQL if that file is present.
App_Data is also registered as the runtime DataDirectory by EShop/Global.asax.cs.
The application is page-based and does not preserve MVC-style extensionless routes.
/Default.aspx: storefront landing page with featured products./Products.aspx: complete catalog./ProductDetail.aspx?id={id}: product detail and add-to-cart form./Cart.aspx: cart display, quantity updates, removal, and checkout link./Account/Login.aspx: sign-in, remembered username, and persistent sign-in./Account/Register.aspx: customer registration./Account/Logout.aspx: logout page with POST-backed sign-out./Checkout.aspx: authenticated checkout form./OrderComplete.aspx?number={orderNumber}: authenticated order confirmation./Orders.aspx: authenticated order history./OrderDetail.aspx?number={orderNumber}: authenticated order details scoped to the signed-in customer.
Behavioral constraints implemented in code:
- Unknown products return HTTP 404.
- Missing or inaccessible orders return HTTP 404.
- Protected pages redirect unauthenticated users to the login page with a local
ReturnUrl. - Cart quantities are constrained to
1through99.
If the machine has the complete legacy toolchain, use the intended solution build:
msbuild EShop.sln /t:Clean,Build /p:Configuration=ReleaseRun commands from the repository root. If MSBuild is not on PATH, the installed local toolchain can be invoked directly:
& 'C:\Program Files\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\MSBuild.exe' EShop.sln /t:Clean,Build /p:Configuration=ReleaseThe solution build produces EShop\bin\EShop.dll and EShop.Tests\bin\Release\EShop.Tests.exe, and copies the web assembly beside the test runner. Building the solution does not validate all ASPX/master-page markup; hosted requests are still required.
If that command fails because .NET 2.0 reference assemblies or Web Application targets are missing, you can still perform a limited compatibility compile of the C# code paths with the full-framework compiler:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nologo /target:library /langversion:ISO-2 /optimize+ /out:EShop\bin\EShop.dll /reference:System.dll /reference:System.Configuration.dll /reference:System.Data.dll /reference:System.Web.dll /reference:System.Xml.dll EShop\Properties\AssemblyInfo.cs EShop\Models\Product.cs EShop\Models\CartItem.cs EShop\Models\Cart.cs EShop\Models\Customer.cs EShop\Models\Order.cs EShop\Models\OrderLine.cs EShop\Services\ProductRepository.cs EShop\Services\PasswordHasher.cs EShop\Services\CartSession.cs EShop\Services\CustomerRepository.cs EShop\Services\OrderRepository.cs EShop\Services\Database.cs EShop\BasePage.cs EShop\AuthenticatedPage.cs EShop\Global.asax.cs EShop\Site.master.cs EShop\Default.aspx.cs EShop\Products.aspx.cs EShop\ProductDetail.aspx.cs EShop\Cart.aspx.cs EShop\Account\Login.aspx.cs EShop\Account\Register.aspx.cs EShop\Account\Logout.aspx.cs EShop\Checkout.aspx.cs EShop\OrderComplete.aspx.cs EShop\Orders.aspx.cs EShop\OrderDetail.aspx.csThe fallback command above intentionally fails for the membership-type upgrade example below. To use it for limited validation on CLR 4, add /reference:System.Web.ApplicationServices.dll to that command without adding the reference to the .NET 2.0 project. A successful fallback compile is not a substitute for a true ASP.NET Web Application build; it proves ISO-2 C# compatibility against the installed CLR 4 assemblies only.
Account registration uses MembershipCreateStatus.Success and MembershipCreateStatus.DuplicateEmail to represent the existing repository result. Registration behavior is otherwise unchanged.
This exercises Microsoft's documented membership-type assembly move:
- In .NET Framework 2.0,
MembershipCreateStatusis in the already-referencedSystem.Web.dll. - In .NET Framework 4.x, it is forwarded to
System.Web.ApplicationServices.dll, which this project deliberately does not reference. - Retargeting to 4.8.1 without fixing references fails with
CS1069and relatedCS0103errors in registration code. This is a source compilation issue, not a claim that existing .NET 2.0 binaries always fail under CLR 4.
From a Visual Studio Developer PowerShell, reproduce without changing the project target or replacing the site's binaries:
msbuild EShop/EShop.csproj /t:Rebuild /p:TargetFrameworkVersion=v4.8.1 /p:OutputPath="$env:TEMP/EShop-breaking-change-probe/bin/" /p:IntermediateOutputPath="$env:TEMP/EShop-breaking-change-probe/obj/"The upgrade agent should add <Reference Include="System.Web.ApplicationServices" /> when retargeting the project to 4.8.1, rebuild, and verify successful and duplicate-email registration. Keep that reference out of the .NET 2.0 baseline. Some upgrade tools may add it automatically; in that case they have already handled this example.
The target-only failure was reproduced locally. The native .NET 2.0 baseline now builds with the installed legacy prerequisites. A CLR 4 fallback compile alone does not establish .NET 2.0 runtime compatibility.
The trailing-semicolon example from Microsoft's stricter ASP.NET page parser guidance was removed from product details. The installed ASP.NET 2.0.50727.9183 parser also rejects it with "The server tag is not well formed," so it is not a valid upgrade-only failure for this baseline.
After removing the semicolon, /ProductDetail.aspx?id=1 returned HTTP 200 and rendered Aurora Headphones under ASP.NET 2.0. Normal C# compilation does not validate this page's markup; use a hosted request to check parsing. The membership assembly-move and category-filter examples remain in place.
Catalog filtering deliberately extracts a category from Request.FilePath, relying on the ASP.NET 2.0 behavior described in Microsoft's FilePath breaking change. The catalog now links to /Products.aspx/Home and /Products.aspx/Audio.
- Legacy expectation: Home shows two products; Audio shows one; the unfiltered catalog shows six.
- ASP.NET 4 behavior:
Request.FilePathstops at/Products.aspx, so this code finds no category and silently shows all six products. HTTP status remains 200. - Upgrade-agent fix: read and decode the category from
Request.PathInfo(removing its leading slash), retaining the unfiltered behavior for an empty category. Do not change the expected counts to accept the regression.
The Home-category failure was reproduced on the CLR 4 fallback host. Native .NET 2.0 behavior is based on the documented contract and remains unverified locally.
After compiling the test runner, enable the opt-in hosted regression test against a running site (use a base URL ending with /):
$env:ESHOP_HOSTED_TEST_URL = 'http://localhost:51335/'
try {
& .\EShop.Tests\bin\Release\EShop.Tests.exe
} finally {
Remove-Item Env:ESHOP_HOSTED_TEST_URL
}HostedCatalogCategoryPathsFilterProducts expects the original behavior and intentionally fails on the unfixed CLR 4 host. The 21 default non-integration checks still pass. No hosted requests are made unless ESHOP_HOSTED_TEST_URL is set.
The solution build above includes the console test runner. Only when using the fallback compiler, build the runner separately after the web assembly is available (create the output directory if needed):
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nologo /target:exe /langversion:ISO-2 /optimize+ /out:EShop.Tests\bin\Release\EShop.Tests.exe /reference:System.dll /reference:System.Data.dll /reference:System.Web.dll /reference:System.Xml.dll /reference:EShop\bin\EShop.dll EShop.Tests\Program.csWhen using the direct csc.exe path, stage a fresh copy of the rebuilt web assembly beside the test runner before executing tests:
Copy-Item EShop\bin\EShop.dll EShop.Tests\bin\Release\EShop.dll -ForceRun non-integration checks:
EShop.Tests\bin\Release\EShop.Tests.exeRun integration-enabled checks:
$env:ESHOP_INTEGRATION_TESTS='1'
EShop.Tests\bin\Release\EShop.Tests.exeThe integration suite expects LocalDB and SqlLocalDB.exe to be installed and usable by the current user.
This repository does not include a self-hosted server. To run the site, use a compatible ASP.NET Web Forms host that can load a legacy Web Application project.
Typical requirements:
- IIS or an equivalent ASP.NET host with the .NET Framework 2.0 runtime available.
- ASP.NET enabled for that host.
- The application rooted at EShop.
- The
EShopDatabaseconnection string left intact unless you intentionally replace it with another SQL Server endpoint.
After a native .NET 2.0 solution build, start the locally installed x86 IIS Express from the repository root:
& 'C:\Program Files (x86)\IIS Express\iisexpress.exe' /path:"$PWD\EShop" /port:51335 /clr:v2.0Open http://localhost:51335/Default.aspx. Keep the host running while browsing or running hosted checks, and press Ctrl+C in its terminal to stop it. If the port is already in use, choose another port and update ESHOP_HOSTED_TEST_URL accordingly. Do not use CLR 4 fallback binaries to validate the CLR 2 baseline; rebuild the solution for v2.0 first.
If no compatible ASP.NET host is installed, repository validation is limited to compilation, static page-contract checks, and the console test harness.
Use these page flows for manual verification once the site is hosted:
- Open
/Default.aspxand confirm featured products render. - Open
/Products.aspxand confirm six products render. Follow Home and Audio and check for two and one products respectively; the unfixed CLR 4 host is expected to fail these category checks. - Open
/ProductDetail.aspx?id=1, add a quantity within1to99, and confirm the cart count updates. - Open
/Cart.aspx, update a quantity, remove an item, and confirm totals refresh. - Open
/Account/Register.aspx, create a new account, and confirm duplicate email registration is rejected on repeat submission. - Open
/Account/Login.aspx, verify remembered username behavior, and verify persistent sign-in when requested. - Attempt to open
/Checkout.aspxwhile signed out and confirm the request redirects to login with a local return URL. - Sign in, open
/Checkout.aspx, place an order, and confirm redirection to/OrderComplete.aspx?number=.... - Open
/Orders.aspxand confirm only the signed-in customer orders are listed. - Open
/OrderDetail.aspx?number=...for the new order and confirm the detail renders. - While signed in as a different customer, request another customer's order number and confirm HTTP 404.
- Open
/Account/Logout.aspx, submit the logout form, and confirm the session ends and the app redirects home.
- This is a sample storefront, not a production-ready commerce system.
- Passwords use a per-user salt and SHA-256 hashing for compatibility with the reference behavior, but the overall identity stack is intentionally minimal.
- Forms Authentication and session state are local to the web application instance.
- The remembered-username cookie is separate from the authentication cookie and is intended only for convenience.
- Output encoding is applied for order/customer render paths, but the app should still be treated as sample code rather than a hardened deployment baseline.
- The catalog is in-memory sample data and is not editable through the UI.
- Orders and customers are stored in LocalDB for local/sample use.
- EShop: web application.
- EShop.Tests: console-based automated checks and compatibility scans.
- docs/superpowers: design and task-planning artifacts.