tags:

views:

147

answers:

4

I see that version 2 of MVC.NET now has a RequireHttps attribute, which works great for me. However, what's a good strategy for turning the effect off? For example, I want to use Https on some pages, but regular Http on others. Should I create my own RequireHttp attribute?

EDIT: I'm using my own RequireHttp attribute, and it works fine, but I'm wondering if there's some built-in functionality in MVC.NET Version 2 that I'm missing.

EDIT 2: I must not have been clear. My question concerns the following: if you use RequireHttps, then any requests after that will be over Https even if the Controller or Action is not decorated with RequireHttps. Unless I'm mistaken, you need a 2nd attribute such as RequireHttp to redirect requests to Http instead of Https.

+3  A: 

The point of the ActionFilterAttribute is that you can apply them to any actions you want. Or in other words, you don't have to apply them to all the actions.

If you don't want an attribute's logic injected into an action, then simply don't apply the attribute to it. For example :

public class SomeController : Controller {
    [RequireHttps]
    public ActionResult SomeAction() {
        //the attribute's logic will be injected to this action.
        return View();
    }

    public ActionResult SomeOtherAction() {
        //this action doesn't require https protocol
        return View();
    }
}

If you apply the attribute to the controller itself, then it will be applied to all the actions in the controller.

Edit :

To require http protocol instead of https, I think you can use the attribute below. I will double check to see if MVC 2 has this already. But if it doesn't (It doesn't) :

public class RequireHttp : ActionFilterAttribute {
   public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if (filterContext.HttpContext.Request.IsSecureConnection) {
            UriBuilder builder = new UriBuilder() {
                Scheme = "http",
                Host = filterContext.HttpContext.Request.Url.Host,
                Path = filterContext.HttpContext.Request.RawUrl
            };

            filterContext.Result = new RedirectResult(builder.ToString());
            filterContext.Result.ExecuteResult(filterContext);
        }
        base.OnActionExecuting(filterContext);
    }
}
çağdaş
Please see my Edit 2.
Slack
@Bob, edited the answer.
çağdaş
@Bob, looking at the source code, I don't think there's already a `RequireHttp` attribute. So yes, you're going to have to roll your own.
çağdaş
@çağdaş Thank you! This helped me a lot.
Zack Peterson
A: 
[RequireHttps] //apply to all actions in controller
public class SomeController
{
    //... or ...
    [RequireHttps] //apply to this action only
    public ActionResult SomeAction()
    {
    }
}

Applying it at the controller level also applies it to all action methods, otherwise apply it to each individual Action method.

David Liddle
Please see my Edit 2.
Slack
+1  A: 

You could apply the attribute either at the controller in which case it will apply for all actions, or only on selected actions.

//apply to all actions
[RequireHttps] 
public class SomeController 
{
    //apply to this action only
    [RequireHttps] 
    public ActionResult SomeAction()
    {
    }

}
Darin Dimitrov
Please see my Edit 2.
Slack
Consecutive requests won't necessary all be on HTTPS. They will use the scheme defined in your action links and forms, so you could setup the desired scheme when generating your links.
Darin Dimitrov
Re: your 24-Oct-2009 comment. Thanks -- it hadn't occurred to me to simply redirect to HTTP in the links from my View.
Slack
@bob but don't you then end up with those messages about changing from secure connection to insecure connection in certain browsers?
Simon_Weaver
A: 

It worked for me!

I converted the çağdaş answer to Visual Basic:

Public Class RequireHttpAttribute
    Inherits ActionFilterAttribute

    Public Overrides Sub OnActionExecuting(ByVal filterContext As _
                                           ActionExecutingContext)
        If (filterContext.HttpContext.Request.IsSecureConnection) Then
            Dim builder As UriBuilder = New UriBuilder()
            builder.Scheme = "http"
            builder.Host = filterContext.HttpContext.Request.Url.Host
            builder.Path = filterContext.HttpContext.Request.RawUrl

            filterContext.Result = New RedirectResult(builder.ToString())
            filterContext.Result.ExecuteResult(filterContext)
        End If

        MyBase.OnActionExecuting(filterContext)
    End Sub

End Class

I use it like this:

<RequireHttp()> _
Public Class SomeController

    <RequireHttp()> _
    Function SomeAction(...) As ActionResult
        ...
    End Function

End Class

I'm also using Joel Mueller's RemoteRequireHttps described here:
ASP.NET MVC RequireHttps in Production Only

Zack Peterson