Após pesquisar em voz alta, consegui resolver esse problema com o IIS Express e uma substituição do método OnAuthorization da classe Controller (Ref # 1). Eu também segui a rota recomendada por Hanselman (Ref # 2). No entanto, eu não estava completamente satisfeito com essas duas soluções devido a dois motivos: 1. A OnAuthorization da referência nº 1 funciona apenas no nível da ação, não na classe da controladora 2. A referência nº 2 requer muita configuração (Win7 SDK for makecert ), comandos netsh e, para usar a porta 80 e a porta 443, preciso iniciar o VS2010 como administrador, com o qual desaprovo.
Então, eu vim com esta solução que se concentra na simplicidade com as seguintes condições:
Quero poder usar o attbbute RequireHttps na classe ou nível de ação do Controller
Quero que o MVC use HTTPS quando o atributo RequireHttps estiver presente e use HTTP se ele estiver ausente
Não quero ter que executar o Visual Studio como administrador
Quero poder usar as portas HTTP e HTTPS atribuídas pelo IIS Express (consulte a Nota 1)
Posso reutilizar o certificado SSL autoassinado do IIS Express e não me importo se vir o prompt SSL inválido
Desejo que o desenvolvedor, o teste e a produção tenham exatamente a mesma base de código e o mesmo binário, além de serem independentes de configurações adicionais (por exemplo, usando netsh, snap-in de certificação mmc etc.)
Agora, com o plano de fundo e a explicação fora do caminho, espero que esse código ajude alguém e economize algum tempo. Basicamente, crie uma classe BaseController que herda do Controller e obtenha suas classes de controlador dessa classe base. Desde que você leu até aqui, presumo que você saiba como fazer isso. Então, feliz codificação!
Nota # 1: Isso é alcançado pelo uso de uma função útil 'getConfig' (consulte o código)
Ref # 1: http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
Ref # 2: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
========== Código no BaseController ===================
#region Override to reroute to non-SSL port if controller action does not have RequireHttps attribute to save on CPU
// By L. Keng, 2012/08/27
// Note that this code works with RequireHttps at the controller class or action level.
// Credit: Various stackoverflow.com posts and http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// if the controller class or the action has RequireHttps attribute
var requireHttps = (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0
|| filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0);
if (Request.IsSecureConnection)
{
// If request has a secure connection but we don't need SSL, and we are not on a child action
if (!requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "http",
Port = int.Parse(getConfig("HttpPort", "80")) // grab from config; default to port 80
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
else
{
// If request does not have a secure connection but we need SSL, and we are not on a child action
if (requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "https",
Port = int.Parse(getConfig("HttpsPort", "443")) // grab from config; default to port 443
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
base.OnAuthorization(filterContext);
}
#endregion
// a useful helper function to get appSettings value; allow caller to specify a default value if one cannot be found
internal static string getConfig(string name, string defaultValue = null)
{
var val = System.Configuration.ConfigurationManager.AppSettings[name];
return (val == null ? defaultValue : val);
}
============== código final ================
No Web.Release.Config, adicione o seguinte para limpar o HttpPort e o HttpsPort (para usar o padrão 80 e 443).
<appSettings>
<add key="HttpPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
<add key="HttpsPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
</appSettings>