После исследования aroud я смог решить эту проблему с помощью IIS Express и переопределения метода OnAuthorization класса Controller (Ссылка № 1). Я также пошел по маршруту, рекомендованному Хансельманом (ссылка №2). Однако я не был полностью удовлетворен этими двумя решениями по двум причинам: 1. OnAuthorization Ref # 1 работает только на уровне действия, а не на уровне класса контроллера 2. Ref # 2 требует большой настройки (Win7 SDK для makecert ), команды netsh и, чтобы использовать порт 80 и порт 443, мне нужно запустить VS2010 от имени администратора, что я не одобряю.
Итак, я придумал это решение, которое фокусируется на простоте со следующими условиями:
Я хочу иметь возможность использовать атрибут RequireHttps на уровне класса или действия контроллера
Я хочу, чтобы MVC использовал HTTPS, когда присутствует атрибут RequireHttps, и использовал HTTP, если он отсутствует
Я не хочу запускать Visual Studio от имени администратора
Я хочу иметь возможность использовать любые порты HTTP и HTTPS, назначенные IIS Express (см. Примечание № 1)
Я могу повторно использовать самоподписанный сертификат SSL IIS Express, и мне все равно, если я увижу недопустимое приглашение SSL
Я хочу, чтобы разработчики, тестовые и продакшн имели одну и ту же базу кода и один и тот же двоичный файл и были максимально независимы от дополнительных настроек (например, с использованием оснастки для сертификатов netsh, mmc и т. Д.).
Теперь, когда предыстория и объяснения разошлись, я надеюсь, что этот код кому-то поможет и сэкономит время. По сути, создайте класс BaseController, который наследуется от Controller, и унаследуйте классы контроллера от этого базового класса. Поскольку вы дочитали до этого места, я предполагаю, что вы знаете, как это делать. Итак, удачного кодирования!
Примечание №1: это достигается за счет использования полезной функции getConfig (см. Код)
Ссылка № 1: http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
Ссылка № 2: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
========== Код в 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);
}
============== конечный код ================
В Web.Release.Config добавьте следующее, чтобы очистить HttpPort и HttpsPort (чтобы использовать значения по умолчанию 80 и 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>