Nos dias sombrios do .NET 1.1, criei (acho que como todo mundo) uma espécie de sistema MVC para um aplicativo que foi assim.
Uma página foi criada para ser uma espécie de mestre 'falso'. Isso tinha algum encanamento para mostrar menus, scripts, estilos etc.
As 'visualizações' eram controles de usuário individuais.
Havia uma tabela com informações sobre cada visualização. Por exemplo, 'Produto' seria carregado ~/Controls/Product.ascx
em um espaço reservado. A tabela também tinha um campo que continha o nome do tipo da classe de modelo (como se). Cada modelo implementou uma interface conhecida. Essa classe foi instanciada usando Activator.CreateInstance()
e chamada para inicializar e depois foi passada para o próprio controle (inversão de controle?). O controle então chamou vários métodos para obter conjuntos de dados ou outros enfeites. A interface em si foi normalizada para ter os métodos CRUD usuais (leitura / gravação / lista / exclusão). Havia também uma camada DAL / ORM abaixo disso.
Não era bonito, mas funcionava bem. Era fácil testar e desenvolver, e a maioria dos desenvolvedores que entravam a bordo se dava bem rapidamente. Acima de tudo, era relativamente simples de criar.