Minha postagem anterior lidou com como usar a API do Magento com o WCF. Outro aspecto do Magento que encontrei é o suporte extremamente flexível para os temas.
Você pode projetar um novo tema que parece radicalmente diferente do padrão. Você não apenas pode alterar as imagens e cores nas folhas de estilo em cascata, como também pode redefinir as regiões (cabeçalho, conteúdo, rodapé ...) que compõem uma página. Por região, você pode especificar qual HTML é injetado nela. Isso oferece a você o máximo poder de personalização para o seu site.
O tema no ASP.NET é suportado para fora do corpo. Usando a pasta app_themes, você pode personalizar a aparência do seu site, por mais complicado que este sistema possa ser.
O Magento é construído usando o padrão MVC, assim como a estrutura do ASP.NET MVC. E esse é o foco deste artigo. Como vamos implementar a Theming no ASP.NET MVC?
Vamos começar ...
Antes de começarmos a codificar, vamos resumir os objetivos que queremos alcançar. Vamos supor que possuímos uma empresa que importa móveis fabricados na China, Vietnã, South-Corea ... etc. Não vendemos diretamente para os usuários finais, mas para revendedores.
Queremos projetar um aplicativo Web ASP.NET MVC que possa ser usado como um site de comércio eletrônico por todos os nossos revendedores. Cada revendedor tem seu próprio nome de domínio e quer vender seus produtos on -line. Cada um desses domínios está vinculado ao nosso único aplicativo da Web.
A funcionalidade oferecida pelo aplicativo da Web é a mesma para cada revendedor, mas cada revendedor deseja personalizar sua loja on -line aplicando um tema personalizado. Apoiaremos as seguintes situações:
Portanto, temos que descobrir como podemos substituir dinamicamente a folha de estilo (CSS), a página mestre, as visualizações e as visualizações parciais.
Antes de começarmos, precisamos colocar as bases. Vamos começar construindo o básico para um aplicativo de demonstração simples.
Observação : nesta seção, forneço uma rápida visão geral da configuração de um aplicativo de demonstração para que o recurso de tema possa ser demonstrado. Esta é apenas uma abordagem rápida e fácil. O foco deste artigo não está em como projetar um modelo de domínio, projetando sua camada de lógica de negócios ... etc. Então, eu mantenho isso o mais curto possível. Sinta -se à vontade para melhorar.
Banco de dados
Crie um novo banco de dados usando o SQL Server Express (2005 ou 2008). Inspirado no banco de dados Northwind, nomeei meu banco de dados [WindDirection].
Este banco de dados contém exatamente uma tabela chamada [revendedor]. Projete a tabela como mostrado na figura a seguir.
Figura 1 - Tabela [revendedor]
![Tabela de revendedores [Reseller] Table Design](https://images.downcodes.com/uploads/20250616/img_68500176a3ae030.png)
Como você pode ver, a coluna ID é a chave primária e usa a especificação de identidade (= AutoinCrement). Adicione também uma restrição única na coluna de domínio, pois cada revendedor tem seu próprio domínio exclusivo.
Observação : O código -fonte que acompanha este artigo contém um script (DDL.SQL) que permite gerar rapidamente esta tabela se não quiser projetá -la manualmente.
A última parte da configuração do nosso banco de dados está inserindo alguns registros fictícios para a tabela [revendedora]. Por favor, insira os seguintes registros:
Figura 2 - revendedores

Temos quatro revendedores. O primeiro revendedor não tem tema personalizado e volta ao padrão. Todos os outros têm seu próprio tema personalizado definido.
Inicie o Visual Studio 2008 e crie uma nova solução em branco intitulada "MVCApplication". Adicione uma nova biblioteca de código e chame -a de "CGEERS.WindDirection.Database". Exclua o arquivo Class1.css gerado automaticamente.
Em seguida, adicione um novo item LINQ às classes SQL e nomeie -o como "DATACLASSES". Renomeie o novo DataContext para "WindDirectionDatacontext". Agora arraste a tabela [revendedor] da guia do servidor Explorer para o LINQ para a superfície do designer SQL.
Figura 3 - Entidade do revendedor

Defina a propriedade de conexão do DataContext como "Nenhum" e exclua a configuração do aplicativo de conexão e o arquivo de configuração do aplicativo (App.config). Não gosto do fato de que o Visual Studio injeta a sequência de conexão para mim. Eu gosto de fazer isso sozinho.
É por isso que adicionei a seguinte classe parcial a esta montagem, que lida com a inicialização do datacontext com uma string de conexão. A única parte com a qual devemos concordar é que a sequência de conexão é chamada de "direção do vento".
Listagem 1 - WindDirectionDatacontext Classe
public partial class WindDirectionDataContext
{
private static readonly string ConnectionString ;
static WindDirectionDataContext ( )
{
ConnectionStringSettings settings = ConfigurationManager . ConnectionStrings [ "WindDirection" ] ;
ConnectionString = settings != null ? settings . ConnectionString : String . Empty ;
}
public WindDirectionDataContext ( ) : base ( ConnectionString ) { }
}Não se esqueça de adicionar uma referência ao conjunto System.Configuration. Contanto que você inclua uma sequência de conexão chamada "Winddirection" nos aplicativos que referenciam esta montagem, ele funcionará muito bem.
Estamos quase lá. Apenas espere, vamos fazer isso. Agora adicione uma nova biblioteca de código à solução chamada "cgeers.winddirection.managers". Exclua o arquivo Class1.cs gerado automaticamente e adicione uma referência ao conjunto System.data.linq.
Adicione uma nova classe chamada gerente e adicione o seguinte código a ele:
Listagem 2 - Gerente de Resumo
public abstract class Manager
{
protected Manager ( )
{
Context = new WindDirectionDataContext ( ) ;
}
public WindDirectionDataContext Context { get ; set ; }
}Esta classe muito simples cria um novo datacontext no qual podemos liberar nossas consultas LINQ posteriormente.
Em seguida, adicione uma classe chamada "ResellerManager" ao projeto e adicione o código mostrado na Listagem 3.
Listagem 3 ResellerManager
public class ResellerManager : Manager
{
public string GetThemeForDomain ( string domain )
{
var q = from r in Context . Resellers
where r . Domain == domain
select r . Theme ;
string theme = q . SingleOrDefault ( ) ;
return ! String . IsNullOrEmpty ( theme ) ? theme : "Default" ;
}
}Esta aula de gerente desce da nossa classe de gerente abstrata e adiciona um método chamado getThemefordOMain (...). Este método procura o tema de um revendedor com base em um determinado nome de domínio. Como cada domínio está excitado a um revendedor, isso não apresenta problemas.
Voila, esse é todo o acesso de dados necessário para o nosso aplicativo de demonstração. Precisamos descobrir o tema de um revendedor com base no domínio da solicitação recebida e, em seguida, temos que aplicá -lo.
Observação : Cuidado ao usar o contexto LINQ para SQL em um aplicativo alimentado por ASP.NET. Embora não seja demonstrado neste artigo, porque ele distrairia muito o nosso principal empreendimento, é aconselhável criar apenas um contexto por solicitação. Armazene o contexto no httpcontext da solicitação para que você possa acessá -lo o tempo todo durante a solicitação.
Há algum tempo, escrevi um artigo especificamente sobre isso, confira o artigo da Entity Framework ObjectContext aqui. Embora lida com a estrutura da entidade em vez do LINQ para o SQL, ele ainda é aplicável.
A etapa final para concluir nosso aplicativo de demonstração básica é adicionar um novo projeto de site à solução. Adicione um novo projeto à solução com base no modelo de projeto de aplicativo da web do ASP.NET MVC e nomeie -o como "MVCAPLACIONAL". Você será perguntado se você também deseja criar um projeto de teste de unidade para este aplicativo. Escolha "Não" para pular isso, pois não precisamos dele para este artigo.
O Visual Studio gerará um aplicativo "Hello, World!"-Tipo ASP.NET MVC que contém várias páginas padrão (domicílio, sobre, logon ... etc.). Adicione sua string de conexão ao arquivo web.config e adicione referências ao cgeers.winddirection.database e cgeers.winddirection.managers Assemblies.
Observação : o web.config contém uma série de definições de configuração referentes à associação do ASP.NET, perfil, funções ... provedores. Você pode ir em frente e excluí -los como não precisamos deles.
Seu explorador de solução deve se parecer com a Figura 4.
Figura 4 - Solution Explorer

Observação : No momento da redação deste artigo, estou usando o ASP.NET MVC versão 1.0. No entanto, a versão 2.0 será lançada em um futuro próximo.
Ao executar o aplicativo da Web, a primeira coisa que precisa descobrir é o tema que ele precisa aplicar. Isso precisa ser feito para cada solicitação. Portanto, conectar um módulo HTTP personalizado na linha de solicitação parece apropriado.
Adicione uma nova classe ao projeto MVCApplication e chame -o de temaHttpmodule. Peça à classe que implemente a interface iHTTPModule. Todo o código para esta classe é mostrado na Listagem 4.
Este artigo não é uma cartilha sobre a redação de módulos HTTP; portanto, se você precisar de mais informações, confira o artigo "Passo a passo: criando e registrando um módulo HTTP personalizado" no MSDN.
Listagem 4 - ThemeHttpmodule
public class ThemeHttpModule : IHttpModule
{
public void Init ( HttpApplication application )
{
application . BeginRequest += application_BeginRequest ;
}
private void application_BeginRequest ( object sender , EventArgs e )
{
HttpApplication application = ( HttpApplication ) sender ;
HttpContext context = application . Context ;
if ( context . Cache == null )
{
return ;
}
string domain = context . Request . Url . GetDomain ( ) ;
string cacheKey = String . Format ( CultureInfo . InvariantCulture , "theme_for_{0}" , domain ) ;
if ( context . Cache [ cacheKey ] == null )
{
ResellerManager manager = new ResellerManager ( ) ;
string theme = manager . GetThemeForDomain ( domain ) ;
context . Cache [ cacheKey ] = theme ;
}
}
public void Dispose ( ) { }
}Este módulo HTTP adiciona um manipulador de eventos para o evento BeginRequest. Este evento ocorre como o primeiro evento na cadeia de execução HTTP Pipeline quando o ASP.NET responde a uma solicitação.
Aqui, extraímos o nome de domínio da solicitação recebida. Em seguida, recuperamos o tema para esse domínio usando o método GetThemefordomain (...) do revendedor. O resultado é então armazenado em cache. Na próxima vez que uma solicitação para esse domínio for acionada, o tema será recuperado do cache e nenhuma consulta de banco de dados será disparada.
O método getDomain () é um método de extensão para a classe URI. Confira o código -fonte deste artigo para ver como ele funciona. De uma maneira semelhante, você pode optar por extrair o subdomínio (por exemplo: www, admin ... etc) da solicitação. Você pode expandir seu mecanismo de elementos para aplicar temas diferentes para cada subdomínio de um domínio.
Por último, mas não menos importante, registre o temaHttpmodule, criando uma entrada no arquivo web.config. Isso é necessário para assinar o módulo HTTP nas notificações de linha de solicitação.
Listagem 5 - Registre o temaHttpmodule
< httpModules >
< add name = " ThemeHttpModule " type = " MvcApplication.ThemeHttpModule " />
<!-- ... -->
</ httpModules >Ao iniciar o aplicativo da Web, receberá a aparência padrão e a aparência exibida na Figura 5. O Visual Studio gerará algumas páginas padrão (domicílio, sobre, logon ... etc.) Incluindo uma página mestre e uma folha de estilo. Usaremos esses arquivos para compensar nosso tema padrão.
Figura 5 - tema padrão do aplicativo ASP.NET MVC

Por padrão, todos os arquivos são salvos nas pastas de conteúdo e visualizações. Precisamos implementar nossa própria estrutura de diretório para que possamos agrupar logicamente nossos temas. Portanto, crie uma nova pasta chamada temas. Crie uma subpasta para o diretório de temas e chame -o de padrão. Mova o diretório de conteúdo e visualizações neste diretório padrão.
Depois de mover as pastas de conteúdo e visualizações, você precisa ajustar a propriedade MasterpageFile da diretiva da página para cada uma das visualizações! O valor antigo faz referência a um local que não existe mais. Alterar MasterPageFile = "~/Views/Shared/Site.master" para MasterPageFile = "~/temas/default/views/shared/site.master" !
Figura 6 - Tema padrão

Voila, nosso tema padrão foi configurado. Se você deseja criar um novo tema, só precisa criar uma nova pasta e colocá -la na pasta de temas. Como você pode ver na captura de tela anterior, criaremos outros temas (verde, laranja, vermelho) mais tarde.
Acabamos de mudar nossas páginas mestras, folhas de estilo, vistas ... etc. para outro diretório. Se iniciarmos nosso aplicativo da web agora, receberemos a seguinte exceção:
Figura 7 - InvalidoperationException

A visualização 'Índice' ou seu mestre não foi encontrado. Os seguintes locais foram pesquisados:
O MVC está tentando localizar uma visualização para a sua página de início padrão, mas não consegue encontrá -la nos locais padrão que ele pesquise assim, você recebe uma exceção. Mudamos esses arquivos para a nossa pasta de temas padrão e em breve criaremos outros temas. Precisamos de uma maneira de informar o MVC sobre os locais onde procurar suas opiniões, página mestre, visualizações parciais ... etc. Esses locais diferem dependendo o tema do revendedor.
Então, basicamente, tudo o que precisamos fazer para apoiar o THE THERSing no ASP.NET MVC é:
Para fazer isso, precisamos escrever nosso próprio mecanismo de visualização. O MVC usa um mecanismo de exibição para renderizar páginas para a resposta. Este mecanismo de exibição é responsável por localizar a página mestre, visualizações e visualizações parciais. Por padrão, o WebFormViewEngine é usado.
Precisamos substituir esse mecanismo de visualização padrão por conta própria. Para fazer isso, adicione uma nova classe chamada ThemedViewEngine ao projeto MVCApplication e desça da classe WebFormViewEngine.
Listagem 6 - TEMEDVIELENGINE
public class ThemedViewEngine : WebFormViewEngine
{
#region Constructor(s)
// Replace the default search paths by our own.
public ThemedViewEngine ( )
{
// Search paths for the master pages
base . MasterLocationFormats = new [ ]
{
"~/Themes/{2}/Views/{1}/{0}.master" ,
"~/Themes/{2}/Views/Shared/{0}.master"
} ;
// Search paths for the views
base . ViewLocationFormats = new [ ]
{
"~/Themes/{2}/Views/{1}/{0}.aspx" ,
"~/Themes/{2}/Views/{1}/{0}.ascx" ,
"~/Themes/{2}/Views/Shared/{0}.aspx" ,
"~/Themes/{2}/Views/Shared/{0}.ascx" ,
} ;
// Search parts for the partial views
// The search parts for the partial views are the same as the regular views
base . PartialViewLocationFormats = base . ViewLocationFormats ;
}
#endregion
}No construtor deste novo mecanismo de exibição, definimos os MasterLocationFormats, ViewLocationFormats e ParcialViewLocationFormats para novos locais, por exemplo: ~/temas/{2}/views/{1}/{0} .aspx.
Cada caminho contém 3 partes que são determinadas dinamicamente.
Para usar o novo mecanismo de exibição, você precisa registrá -lo. Faça isso adicionando o código a seguir ao manipulador de eventos Application_Start, localizado no arquivo global.asax.cs.
Listagem 7 - Registre o The ThemedViewEngine
protected void Application_Start ( )
{
ViewEngines . Engines . Clear ( ) ;
ViewEngines . Engines . Add ( new ThemedViewEngine ( ) ) ;
RegisterRoutes ( RouteTable . Routes ) ;
}Aqui você limpa qualquer mecanismo de visualização que possa ter sido carregado anteriormente e injete o seu próprio. Agora, tudo o que resta é instruir o mecanismo de visualização como formatar os novos caminhos de pesquisa, para que ele encontre corretamente os arquivos solicitados. Para fazer isso, você precisa substituir os dois métodos a seguir:
Listagem 8 - Métodos FindPartialView (...) e FindView (...)
public override ViewEngineResult FindPartialView ( ControllerContext controllerContext , string partialViewName , bool useCache )
public override ViewEngineResult FindView ( ControllerContext controllerContext , string viewName , string masterName , bool useCache )Não vou incluir o código para essas duas funções aqui, porque é bastante demorado e tem algumas referências a métodos privados de auxiliar. Basicamente, esses dois métodos seguem o mesmo padrão:
Portanto, nosso novo mecanismo de exibição basicamente pesquise nossa pasta de temas e, se não conseguir encontrar a página mestre solicitada, a visualização ou a visualização parcial, usa a do tema padrão. É claro que o tema padrão precisa ser completo e não pode ter arquivos ausentes.
Isso permite criar temas que contêm apenas uma página mestre que, por sua vez, faz referência a uma folha de estilo diferente ou temas que contêm visualizações e / ou vistas parciais apenas para as seções que você deseja estilizar de maneira diferente.
Seguindo esse padrão, você pode criar temas que substituem apenas certas visualizações e recuam nas visualizações do tema padrão se nenhuma visualização personalizada for fornecida.
Baseei meu mecanismo de visão no trabalho do excelente artigo de Chris Pietschmann sobre temas no ASP.NET MVC. Sugiro que você consulte o artigo dele, pois ele contém mais informações sobre como o mecanismo de exibição funciona internamente.
Com o novo mecanismo de exibição no lugar, podemos executar o aplicativo da web novamente sem exceções, pois agora ele pode resolver as solicitações da página mestre, visualizações e visualizações parciais.
Observação : alterei um pouco o código para que, quando o mecanismo de visualização não pudesse resolver uma solicitação para uma determinada página mestre, visualização ou visualização parcial, ele recorre aos encontrados no tema padrão. Portanto, não se esqueça de conferir o código -fonte deste artigo também.
Vamos criar rapidamente um novo tema. Adicione uma nova pasta chamada "Red" na pasta de temas. Copie o site.master e o site.css do tema padrão, conforme mostrado na figura a seguir.
Figura 8 - Tema vermelho

Abra a folha de estilo do tema vermelho e altere a propriedade cor de fundo do elemento corporal. Defina -o como vermelho. Agora abra a tabela [revendedor] e defina o campo tema como "vermelho" para o revendedor cujo domínio está definido como localhost. Reinicie o aplicativo da web e agora ele deve estar usando a página mestre e a folha de estilo do tema vermelho.
Figura 9 - Tema vermelho em ação

Da mesma forma, você pode criar um tema laranja que não apenas contém uma página mestre, mas também uma visão diferente para a página inicial.
Figura 10 - Tema Orange

O tema laranja renderizará a nova visualização da página inicial em vez da visualização padrão. Se você deseja substituir uma visualização parcial, pode fazê -lo da mesma maneira. Basta copiar a visualização parcial padrão para o mesmo local sob a nova pasta de temas e ajustá -la conforme necessário.
Para cada tema, agora você pode servir diferentes páginas, vistas e vistas parciais. Há um cenário restante que desejo apoiar. Os revendedores que estão satisfeitos com a visualização padrão, mas que apenas desejam ajustar o logotipo, algumas cores ... etc. pode ser facilmente contente aplicando uma folha de estilo diferente ao tema padrão.
Adicione uma nova pasta de temas no diretório de temas e chame -o de verde. Copie a folha de estilo do tema padrão para o tema verde, conforme mostrado na figura a seguir.
Figura 11 - Tema verde

Abra a folha de estilo do tema verde e ajuste a propriedade cor de fundo do elemento corporal para verde. Se você definir o tema para o revendedor com o domínio localhost para verde e iniciar o aplicativo, você notará que ele ainda está usando a folha de estilo do tema padrão.
Isso é causado pelo fato de o tema verde não ter sua própria página mestre. Ele usa a página mestre do tema padrão e esta página mestre faz referência à sua própria folha de estilo.
Abra a página mestre do tema padrão e substitua a linha:
< link href =" ../../Content/Site.css " rel =" stylesheet " type =" text/css " />com
< link href =" <% " ="Html.GetThemedStyleSheet()" % /> rel="stylesheet"
type="text/css" / >O método getThemedStylesheet () é um método de extensão para a classe de utilitário html. Adicione uma nova classe chamada htmlhelperextensions ao projeto e adicione o seguinte código a ele.
Listagem 9 - HtmlHelperextensions
public static class HtmlHelperExtensions
{
public static string GetThemedStyleSheet ( this HtmlHelper html )
{
HttpContext context = HttpContext . Current ;
if ( context == null )
{
throw new InvalidOperationException ( "Http Context cannot be null." ) ;
}
string defaultStyleSheet = context . Server . MapPath ( "~/Themes/Default/Content/Site.css" ) ;
string domain = context . Request . Url . GetDomain ( ) ;
string cacheKey = String . Format ( CultureInfo . InvariantCulture , "theme_for_{0}" , domain ) ;
string theme = ( string ) context . Cache [ cacheKey ] ;
if ( String . IsNullOrEmpty ( theme ) || theme == "Default" )
{
return defaultStyleSheet ;
}
string styleSheet = context . Server . MapPath ( String . Format ( CultureInfo . InvariantCulture ,
"~/Themes/{0}/Content/Site.css" , theme ) ) ;
if ( ! File . Exists ( styleSheet ) )
{
styleSheet = defaultStyleSheet ;
}
return String . Format ( CultureInfo . InvariantCulture , "'{0}'" , styleSheet ) ;
}
}O método getThemEdStylesheet () carrega o tema do cache do HTTPAPplication e verifica se esse tema tem sua própria folha de estilo. Caso contrário, ele volta à folha de estilo do tema padrão. O código contém algumas seqüências codificadas, embora não seja ideal, ele faz o truque. Sinta -se à vontade para melhorar esse método.
Se você iniciar o aplicativo da web agora, terá um belo fundo verde.
Este artigo mostra como você pode ativar a temas no ASP.NET MVC. Para isso, você só precisa implementar duas coisas, a saber:
O sistema de tema que implementamos usa um tema padrão e verifica se ele precisa substituir partes desse tema padrão pelo de um tema personalizado. Você pode apoiar facilmente um dos seguintes cenários ou combiná -los: