7

We have a login/register modal that is being called via javascript on the front end. I created a custom route to point to the right action controller, and it works fine in every environment - except when we try with https. So, http://website.com/account/login works, but https://website.com/account/login throws the following error:

Exception type: InvalidOperationException Exception message: Attempt to retrieve context object of type 'Sitecore.Mvc.Presentation.RenderingContext' from empty stack.

The line that this error hits on is this (first line in the login controller):

var datasource = SitecoreContext.GetItem<LoginForm>(RenderingContext.Current.Rendering.DataSource);

Here's the custom routing in RegisterRoutes.cs:

RouteTable.Routes.MapRoute("AccountLogin", "Account/Login", 
    new { controller = "Account", action = "Login" });

Using Sitecore 8.1 rev. 160302.

Edit: I should additionally note that this error is happening only after the user submits login information, but that the line this is hitting is not in the HttpPost version of the controller, which makes this mystery extra puzzling!

Order of operations:

  1. Page hits the login controller (non httppost version) and loads the login view with no issues
  2. Javascript triggers the modal popup and user fills out login information and clicks the submit button
  3. 500 error is thrown and returned to the javascript from the non httppost version of the login controller. (I cannot tell at this point if httppost is also getting hit.)

Additonal Edit: Adding javascript and controller action result methods.

Javascript

    $.ajax({
        url: $form.attr('action'),
        type: 'post',
        dataType: 'json',
        data: $form.serialize()
    })
    .done(function (data) {

      console.log("data");
      console.log(data);

        clearInterval(spinner);

        $self.find(".spinner").hide();

        $(".login-subscribe .tabs .tab:not(.selected) a").removeClass("disabled");

        if ($.isEmptyObject(data)) {
            window.location.reload();
            return;
        }

        if (typeof data !== 'undefined') {
          if ('userRef' in data) {
              $('.modal-overlay').hide();

              //success - do stuff
          }

          if ('errorMsg' in data) {
              $self.prop("disabled", false)
                    .parent()
                    .find("input[required]")
                    .addClass("error")
                    .end()
                    .find(".errorMsg")
                    .html(data.errorMsg)
                    .show();
          }
        }
    })
    .fail(function (error) {
      console.log("fail");
      console.log(error);

        $self.parent()
              .find("input[required]")
              .addClass("error")
              .end()
              .find(".errorMsg")
              .show();
    });

Controller action result methods:

    public ActionResult Login()
    {


        var datasource = SitecoreContext.GetItem<LoginForm>(RenderingContext.Current.Rendering.DataSource);
        if (datasource == null)
        {
            return DataSourceNotConfiguredResult;
        }

        LogInViewModel logInViewModel = new LogInViewModel(datasource);

        return View(Views.LogIn, logInViewModel);

    }

    [HttpPost]
    public ActionResult Login(string Email, string Password, string RememberMe)
    {

        if (!string.IsNullOrWhiteSpace(Email) && !string.IsNullOrWhiteSpace(Password) &&
            !string.IsNullOrWhiteSpace(RememberMe))
        {
            bool rememberMe = false;
            if (RememberMe.ToLower() == "true")
            {
                rememberMe = true;
            }
            Tuple<AccountResultCode, string> loginResult = userAccountUtilities.Login(Email, Password, rememberMe);


            if (loginResult.Item1 == AccountResultCode.Success)
            {

                if (string.IsNullOrWhiteSpace(loginResult.Item2))
                {
                    return Content("{}", "application/json");
                }
                return Content(loginResult.Item2, "application/json");

            }
            else
            {
                string errorMsg = ErrorMessaging(loginResult.Item1);
                errorMsg = "{\"errorMsg\": \"" + errorMsg.Replace("\n", "").Replace("\"", "\\\"") + "\"}";
                return Content(errorMsg, "application/json");

            }


        }
        return Content("");
    }
4
  • You mention that JavaScript is used to trigger a modal dialog for the login submission - this might be a silly question, but just to double check: is the controller that is responding to the modal dialog submission a separate API controller? Commented Oct 18, 2016 at 13:46
  • No, it's a part of the entire account controller that deals with all account related stuff. The custom routing is what points the javascript to the correct action. (And it works just fine when under http.) Commented Oct 18, 2016 at 13:59
  • Can you add the JavaScript to the example so we can see how it is being called? Also maybe add the Controller action result methods with attributes so we can check those.
    – Richard Seal
    Commented Oct 18, 2016 at 14:06
  • Ok, no problem, just added. Commented Oct 18, 2016 at 14:34

2 Answers 2

3

The code looks like it should work. I would make the following changes to just make things a bit more robust:

  1. Add a [HttpGet] attribute to the Login action result. It could be that over https the route is hitting the Get action result first, but because it is not limited to Get it will accept Post also.
[HttpGet]
public ActionResult Login()
  1. Check your $form.attr('action') value. Make sure that this is either a relative path /Account/Login or if it includes the scheme (https/http), make sure the right one is in there.
1
  • Thanks - I'll give these things a try. I do know that the action value is definitely relative. Commented Oct 18, 2016 at 15:29
0

Looks like Form Post is submitting the entire page which intern triggers the all renderings on the page and because Form Post happens outside the Sitecore processing pipeline, it is not able to find the Sitecore rendering context.

2
  • I'm not sure why this would work fine when it's http and not with https though. Commented Oct 18, 2016 at 14:16
  • I agree with you, behavior should be same irrespective of protocol. It is worth looking at fiddler trace for your request and IIS log to see what is getting called and what server is doing for the request.
    – CPrakash
    Commented Oct 19, 2016 at 2:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.