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("");
    }
  • 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? – Chris Smith Oct 18 '16 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.) – Amy Triplett Oct 18 '16 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 Oct 18 '16 at 14:06
  • Ok, no problem, just added. – Amy Triplett Oct 18 '16 at 14:34
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.
| improve this answer | |
  • Thanks - I'll give these things a try. I do know that the action value is definitely relative. – Amy Triplett Oct 18 '16 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.

| improve this answer | |
  • I'm not sure why this would work fine when it's http and not with https though. – Amy Triplett Oct 18 '16 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 Oct 19 '16 at 2:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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