0

I am working on an asp.net MVC3 application.

I have a LiveFeedController with methods that return a list of items based on options that the user selects. It returns a full view or partial view depending on if the request is an ajax request.

For example:

  Public Class LiveFeedController
  Inherits System.Web.Mvc.Controller

        <Authorize(Roles:="CanViewFeed")>
        Function Feed(Optional ByVal feedID As Nullable(Of Guid) = Nothing, Optional ByVal itemID As Nullable(Of Guid) = Nothing, Optional ByVal refreshTimer As Double = 0.0) As ActionResult
            Dim feedVM As New FeedViewModel
            feedVM.SelectedFeedID = feedID 
            feedVM.SelectedItemID = itemID 
            feedVM.RefreshTimer = refreshTimer
            Return View(feedVM)
        End Function

        <Authorize(Roles:="CanViewFeed")>
        <HttpPost()>
        Function Feed(ByVal collection As FormCollection) As ActionResult
            Dim feedVM As New FeedViewModel
            TryUpdateModel(feedVM , collection)
            If Request.IsAjaxRequest Then
                Return PartialView("PartialFeed", feedVM)
            End If
            Return View(feedVM)
        End Function

My problem is that if an ajax request is submitted to the HttpPost method, and the user is no longer logged in (so the Authorize fails), the content returned is my logon page specified in the web.config file:

<authentication mode="Forms">
  <forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>

This is being displayed in a dynamic section of my page/view but it is making the html invalid because the content returned is a full view for the logon page.

I would like too avoid this problem and properly display the content of the log in page. How can I accomplish this?

Thanks,

-Frinny

Frinavale
  • 3,908
  • 10
  • 44
  • 74

1 Answers1

1

I found a solution to my problem by reading through this thread: How to manage a redirect request after a jQuery Ajax call. The solution I used is not marked as the thread's answer.

This is what I did.

In my Global.asax.vb file I implemented a method that handles the PreSendRequestHeaders event. If the Response.StatusCode indicated a redirect (302), and if the Request was an Ajax request, I change the status code to "OK" (200) and added a header that indicates that authentication is required. I also added a header called New_Location that indicates where the browser was supposed to redirect to.

Private Sub MvcApplication_PreSendRequestHeaders(sender As Object, e As System.EventArgs) Handles Me.PreSendRequestHeaders
    If Context.Response.StatusCode = 302 And New HttpContextWrapper(Context).Request.IsAjaxRequest Then
        Context.Response.StatusCode = 200
        Context.Response.AddHeader("REQUIRES_AUTH", "1")
        Context.Response.AddHeader("NEW_LOCATION", Context.Response.RedirectLocation)
    End If
End Sub

Now, in the function that handles my Ajax success event I check to see if the REQUIRES_AUTH header is set to '1' and if it is I redirect the user to the value in the NEW_LOCATION header.

Like this:

var htmlForm = document.getElementById('feedInfoForm');
var form = $('#feedInfoForm');
$.ajax({
        type: htmlForm.method,
        url: htmlForm.action,
        data: form.serialize(),
        cache: false,
        success: function (result, textStatus, xhr) {

            //Checking if the response should have been a redirect
            if (xhr.getResponseHeader('REQUIRES_AUTH') == '1') {
                window.location = xhr.getResponseHeader('NEW_LOCATION'); //redirecting
                XMLHttpRequest.abort(); // terminating further ajax execution
            }

            $('#dynamicFeedContent').html(result);

        },
        error: function (jqXHR, textStatus, errorThrown) {
           var str = textStatus + " " + errorThrown;
            $('#dynamicFeedContent').html(str);
        }
    });

This solution allows me to redirect the window to the full login page to avoid issues with having the login page rendered in the middle of my live feed content.

-Frinny

Community
  • 1
  • 1
Frinavale
  • 3,908
  • 10
  • 44
  • 74