Після дослідження за рахунком я зміг вирішити цю проблему за допомогою IIS Express та переопрацювання методу OnAuthorization класу Controller (Посилання №1). Я також пішов з маршруту, рекомендованого Гензельманом (№№ 2). Однак я не був задоволений цими двома рішеннями з двох причин: 1. OnAuthorization Ref # 1 працює лише на рівні дії, а не на рівні класу контролера. 2. Ref # 2 вимагає багато налаштувань (Win7 SDK для makecert ), команд netsh, і, щоб використовувати порт 80 і порт 443, мені потрібно запустити VS2010 як адміністратор, на що я нахмурився.
Отже, я придумав таке рішення, яке зосереджує увагу на простоті з наступними умовами:
Я хочу мати можливість використовувати аттрибутор RequireHttps на рівні Controller або на рівні дії
Я хочу, щоб MVC використовував HTTPS, коли присутній атрибут RequireHttps, і використовувати HTTP, якщо він відсутній
Мені не хочеться запускати Visual Studio як адміністратор
Я хочу мати змогу використовувати будь-які порти HTTP та HTTPS, призначені IIS Express (Див. Примітку №1)
Я можу повторно використовувати самопідписаний сервер SSL IIS Express, і мені байдуже, чи бачу недійсне запит SSL
Я хочу, щоб розробник, тест і виробництво мали точно таку саму базу коду, таку ж двійкову та незалежну від додаткової настройки (наприклад, використання вбудованого модуля netsh, mmc cert тощо).
Тепер, коли передували та пояснення, я сподіваюся, що цей код комусь допоможе та заощадить час. В основному створіть клас 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>