Developer forum

Forum » Dynamicweb 9.0 Upgrade issues » System.InvalidOperationException in Dynamicweb.Environment.CookieManager.UpdateCookie

System.InvalidOperationException in Dynamicweb.Environment.CookieManager.UpdateCookie

Simon Nordahl
Simon Nordahl
Reply

Hi guys

We're having additional issues with our asynclogin handler.

We're calling the following: 

var loginHandler = new Dynamicweb.Frontend.LoginHandler();

loginHandler.ExtranetLogOn(username, password, true);

But when doing so we get an System.InvalidOperationException: Collection was modified during the first login attempt. (it always work the 2nd attempt).

Stacktrace:

   ved System.Collections.Specialized.NameObjectCollectionBase.NameObjectKeysEnumerator.MoveNext()
   ved Dynamicweb.Environment.CookieManager.UpdateCookie(Cookie cookie)
   ved Dynamicweb.Frontend.LoginHandler.SaveCookie()
   ved Dynamicweb.Frontend.LoginHandler.ExtranetLogin(String username, String password, Boolean onlyActive, Boolean impersonateUser, Int32 impersonateUserID, Boolean loginIfPwdEncrypted)
   ved Dynamicweb.Frontend.LoginHandler.ExtranetLogOn(String username, String password, Boolean onlyActive)

The error seems to lie in Dynamicweb.Environment.CookieManager's UpdateCookie(Cookie cookie) method in the following foreach loop:

            Cookie existingCookie = Context.Current.Response.Cookies[cookie.Name];

            if ((existingCookie != null))
            {
                NameValueCollection cookieValueCollection = cookie.Values;
                foreach (string key in cookieValueCollection.Keys)
                {
                    existingCookie[key] = cookieValueCollection[key];
                }

 

 


Replies

 
Simon Nordahl
Simon Nordahl
Reply

It is worth mentioning that you do get logged in, you just also get an exception in cookiemanager, what the consequence of if it is i dont know.

 
Nicolai Pedersen
Reply

Hm - seems to be that doing this async results in the cookie collection is modified in 2 threads at the same time... And the login and cookiemanagers are not threadsafe.

What is the scenario? Could another approach be used?

 
Simon Nordahl
Simon Nordahl
Reply

How come threading is an issue? The call is made entirely in one request thus one session.

We use it to show a user an error message if he couldn't login and only redirect if the login were successfull, which we belive gives the customer a better experience.

I'm open for suggestions for other implementations, but the overall flow should stay the same.

 
Nicolai Pedersen
Reply

Hi Simon

Why would you need the handler to be async? Is the load really that high it should be?

You can post your entire code and we will look into why it happens.

BR Nicolai

 
Simon Nordahl
Simon Nordahl
Reply

Calling the ffunctionality async would be pushing it. In reality its just a generic handler that recieves an ajax post with the login information.

The handler is pasted below.

using System;
using System.Web;
using System.Web.SessionState;
using Dynamicweb.Frontend;
using Newtonsoft.Json;
using NLog;

namespace StandardWebshop.Handlers
{
    /// <summary>
    /// Summary description for AsyncLogin
    /// </summary>
    public class AsyncLogin : IHttpHandler, IRequiresSessionState
    {
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "application/json";

            var username = context.Request["username"];
            var password = context.Request["password"];

            var loginHandler = new Dynamicweb.Frontend.LoginHandler();

            try
            {
                // You must have a pageview loaded, since ExtranetLogin is dependant on the Pageview
                // being set in the cache. This will set it in the cache...
                new PageView().Load();
                loginHandler.ExtranetLogOn(username, password, true);

            }
            catch (Exception e)
            {
                //Only an error if the user is not logged in.
                if (!loginHandler.UserLoggedIn)
                {
                    _logger.Error(e, $"An error occurred when a user attempted to log in with the username: \"{username}\"");

                    // Trigger the XHR's error callback
                    context.Response.Status = "500 Internal Server Error";
                    context.Response.StatusCode = 500;
                    context.Response.StatusDescription = "An error has occurred";
                }
            }

            var responseData = new LoginAttemptViewModel
            {
                LoginSuccessful = loginHandler.UserLoggedIn
            };


            context.Response.Write(JsonConvert.SerializeObject(responseData));
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        private class LoginAttemptViewModel
        {
            public bool LoginSuccessful { get; set; }
        }
    }
}

 

You must be logged in to post in the forum