Pergunta

Tenho um efeito estranho no meu site quando ele está sob carga pesada.

Recebo aleatoriamente as propriedades das configurações de outros usuários.Eu tenho minha própria implementação do sistema de perfis, então acho que não posso culpar o próprio sistema de perfis.

Eu só preciso de um ponto para começar a depurar.Acho que existe um valor de cookie que mapeia para uma entrada de perfil em algum lugar.Existe alguma chance de ver como esse mapeamento funciona?

Aqui está meu provedor de perfil:

using System;
using System.Text;
using System.Configuration;
using System.Web;
using System.Web.Profile;
using System.Collections;
using System.Collections.Specialized;
using B2CShop.Model;
using log4net;
using System.Collections.Generic;
using System.Diagnostics;
using B2CShop.DAL;
using B2CShop.Model.RepositoryInterfaces;
[assembly: log4net.Config.XmlConfigurator()]
namespace B2CShop.Profile
{
    public class B2CShopProfileProvider : ProfileProvider
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(B2CShopProfileProvider));
        // Get an instance of the Profile DAL using the ProfileDALFactory
        private static readonly B2CShop.DAL.UserRepository dal = new  B2CShop.DAL.UserRepository();
        // Private members
        private const string ERR_INVALID_PARAMETER = "Invalid Profile parameter:";

        private const string PROFILE_USER = "User";
        private static string applicationName = B2CShop.Model.Configuration.ApplicationConfiguration.MembershipApplicationName;

        /// <summary>
        /// The name of the application using the custom profile provider.
        /// </summary>
        public override string ApplicationName
        {
            get
            {
                return applicationName;
            }
            set
            {
                applicationName = value;
            }
        }


        /// <summary>
        /// Initializes the provider.
        /// </summary>
        /// <param name="name">The friendly name of the provider.</param>
        /// <param name="config">A collection of the name/value pairs representing the provider-specific attributes specified in the configuration for this provider.</param>
        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException("config");

            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "B2C Shop  Custom Provider");
            }

            if (string.IsNullOrEmpty(name))
                name = "b2c_shop";

            if (config["applicationName"] != null && !string.IsNullOrEmpty(config["applicationName"].Trim()))
                applicationName = config["applicationName"];

            base.Initialize(name, config);

        }

        /// <summary>
        /// Returns the collection of settings property values for the specified application instance and settings property group.
        /// </summary>
        /// <param name="context">A System.Configuration.SettingsContext describing the current application use.</param>
        /// <param name="collection">A System.Configuration.SettingsPropertyCollection containing the settings property group whose values are to be retrieved.</param>
        /// <returns>A System.Configuration.SettingsPropertyValueCollection containing the values for the specified settings property group.</returns>
        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
        {

            string username = (string)context["UserName"];
            bool isAuthenticated = (bool)context["IsAuthenticated"];
            //if (!isAuthenticated) return null;
            int uniqueID = dal.GetUniqueID(username, isAuthenticated, false, ApplicationName);



            SettingsPropertyValueCollection svc = new SettingsPropertyValueCollection();

            foreach (SettingsProperty prop in collection)
            {
                SettingsPropertyValue pv = new SettingsPropertyValue(prop);

                switch (pv.Property.Name)
                {
                    case PROFILE_USER:
                        if (!String.IsNullOrEmpty(username))
                        {
                            pv.PropertyValue = GetUser(uniqueID);
                        }
                        break;
                    default:
                        throw new ApplicationException(ERR_INVALID_PARAMETER + " name.");
                }

                svc.Add(pv);
            }
            return svc;
        }


        /// <summary>
        /// Sets the values of the specified group of property settings.
        /// </summary>
        /// <param name="context">A System.Configuration.SettingsContext describing the current application usage.</param>
        /// <param name="collection">A System.Configuration.SettingsPropertyValueCollection representing the group of property settings to set.</param>
        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
        {

            string username = (string)context["UserName"];
            CheckUserName(username);
            bool isAuthenticated = (bool)context["IsAuthenticated"];

            int uniqueID = dal.GetUniqueID(username, isAuthenticated, false, ApplicationName);
            if (uniqueID == 0)
            {
                uniqueID = dal.CreateProfileForUser(username, isAuthenticated, ApplicationName);
            }

            foreach (SettingsPropertyValue pv in collection)
            {

                if (pv.PropertyValue != null)
                {
                    switch (pv.Property.Name)
                    {
                        case PROFILE_USER:
                            SetUser(uniqueID, (UserInfo)pv.PropertyValue);
                            break;
                        default:
                            throw new ApplicationException(ERR_INVALID_PARAMETER + " name.");
                    }
                }
            }

            UpdateActivityDates(username, false);
        }


        // Profile gettters
        // Retrieve UserInfo
        private static UserInfo GetUser(int userID)
        {
            return dal.GetUser(userID);
        }




        // Update account info
        private static void SetUser(int uniqueID, UserInfo user)
        {
            user.UserID = uniqueID;
            dal.SetUser(user);
        }


        // UpdateActivityDates
        // Updates the LastActivityDate and LastUpdatedDate values 
        // when profile properties are accessed by the
        // GetPropertyValues and SetPropertyValues methods. 
        // Passing true as the activityOnly parameter will update
        // only the LastActivityDate.
        private static void UpdateActivityDates(string username, bool activityOnly)
        {
            dal.UpdateActivityDates(username, activityOnly, applicationName);
        }

        /// <summary>
        /// Deletes profile properties and information for the supplied list of profiles.
        /// </summary>
        /// <param name="profiles">A System.Web.Profile.ProfileInfoCollection of information about profiles that are to be deleted.</param>
        /// <returns>The number of profiles deleted from the data source.</returns>
        public override int DeleteProfiles(ProfileInfoCollection profiles)
        {

            int deleteCount = 0;

            foreach (ProfileInfo p in profiles)
                if (DeleteProfile(p.UserName))
                    deleteCount++;

            return deleteCount;
        }

        /// <summary>
        /// Deletes profile properties and information for profiles that match the supplied list of user names.
        /// </summary>
        /// <param name="usernames">A string array of user names for profiles to be deleted.</param>
        /// <returns>The number of profiles deleted from the data source.</returns>
        public override int DeleteProfiles(string[] usernames)
        {

            int deleteCount = 0;

            foreach (string user in usernames)
                if (DeleteProfile(user))
                    deleteCount++;

            return deleteCount;
        }

        // DeleteProfile
        // Deletes profile data from the database for the specified user name.
        private static bool DeleteProfile(string username)
        {
            CheckUserName(username);
            return dal.DeleteAnonymousProfile(username, applicationName);   
        }

        // Verifies user name for sise and comma
        private static void CheckUserName(string userName)
        {
            if (string.IsNullOrEmpty(userName) || userName.Length > 256 || userName.IndexOf(",") > 0)
                throw new ApplicationException(ERR_INVALID_PARAMETER + " user name.");
        }

        /// <summary>
        /// Deletes all user-profile data for profiles in which the last activity date occurred before the specified date.
        /// </summary>
        /// <param name="authenticationOption">One of the System.Web.Profile.ProfileAuthenticationOption values, specifying whether anonymous, authenticated, or both types of profiles are deleted.</param>
        /// <param name="userInactiveSinceDate">A System.DateTime that identifies which user profiles are considered inactive. If the System.Web.Profile.ProfileInfo.LastActivityDate value of a user profile occurs on or before this date and time, the profile is considered inactive.</param>
        /// <returns>The number of profiles deleted from the data source.</returns>
        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {

            string[] userArray = new string[0];
             dal.GetInactiveProfiles((int)authenticationOption, userInactiveSinceDate, ApplicationName).CopyTo(userArray, 0);

            return DeleteProfiles(userArray);
        }

        /// <summary>
        /// Retrieves profile information for profiles in which the user name matches the specified user names.
        /// </summary>
        /// <param name="authenticationOption">One of the System.Web.Profile.ProfileAuthenticationOption values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="usernameToMatch">The user name to search for.</param>
        /// <param name="pageIndex">The index of the page of results to return.</param>
        /// <param name="pageSize">The size of the page of results to return.</param>
        /// <param name="totalRecords">When this method returns, contains the total number of profiles.</param>
        /// <returns>A System.Web.Profile.ProfileInfoCollection containing user-profile information
        //     for profiles where the user name matches the supplied usernameToMatch parameter.</returns>
        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {

            CheckParameters(pageIndex, pageSize);

            return GetProfileInfo(authenticationOption, usernameToMatch, null, pageIndex, pageSize, out totalRecords);
        }

        /// <summary>
        /// Retrieves profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the specified user name.
        /// </summary>
        /// <param name="authenticationOption">One of the System.Web.Profile.ProfileAuthenticationOption values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="usernameToMatch">The user name to search for.</param>
        /// <param name="userInactiveSinceDate">A System.DateTime that identifies which user profiles are considered inactive. If the System.Web.Profile.ProfileInfo.LastActivityDate value of a user profile occurs on or before this date and time, the profile is considered inactive.</param>
        /// <param name="pageIndex">The index of the page of results to return.</param>
        /// <param name="pageSize">The size of the page of results to return.</param>
        /// <param name="totalRecords">When this method returns, contains the total number of profiles.</param>
        /// <returns>A System.Web.Profile.ProfileInfoCollection containing user profile information for inactive profiles where the user name matches the supplied usernameToMatch parameter.</returns> 
        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {

            CheckParameters(pageIndex, pageSize);

            return GetProfileInfo(authenticationOption, usernameToMatch, userInactiveSinceDate, pageIndex, pageSize, out totalRecords);
        }

        /// <summary>
        /// Retrieves user profile data for all profiles in the data source.
        /// </summary>
        /// <param name="authenticationOption">One of the System.Web.Profile.ProfileAuthenticationOption values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="pageIndex">The index of the page of results to return.</param>
        /// <param name="pageSize">The size of the page of results to return.</param>
        /// <param name="totalRecords">When this method returns, contains the total number of profiles.</param>
        /// <returns>A System.Web.Profile.ProfileInfoCollection containing user-profile information for all profiles in the data source.</returns>      
        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
            CheckParameters(pageIndex, pageSize);

            return GetProfileInfo(authenticationOption, null, null, pageIndex, pageSize, out totalRecords);
        }

        /// <summary>
        /// Retrieves user-profile data from the data source for profiles in which the last activity date occurred on or before the specified date.
        /// </summary>
        /// <param name="authenticationOption">One of the System.Web.Profile.ProfileAuthenticationOption values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="userInactiveSinceDate">A System.DateTime that identifies which user profiles are considered inactive. If the System.Web.Profile.ProfileInfo.LastActivityDate of a user profile occurs on or before this date and time, the profile is considered inactive.</param>
        /// <param name="pageIndex">The index of the page of results to return.</param>
        /// <param name="pageSize">The size of the page of results to return.</param>
        /// <param name="totalRecords">When this method returns, contains the total number of profiles.</param>
        /// <returns>A System.Web.Profile.ProfileInfoCollection containing user-profile information about the inactive profiles.</returns>
        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            CheckParameters(pageIndex, pageSize);

            return GetProfileInfo(authenticationOption, null, userInactiveSinceDate, pageIndex, pageSize, out totalRecords);
        }

        /// <summary>
        /// Returns the number of profiles in which the last activity date occurred on or before the specified date.
        /// </summary>
        /// <param name="authenticationOption">One of the System.Web.Profile.ProfileAuthenticationOption values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="userInactiveSinceDate">A System.DateTime that identifies which user profiles are considered inactive. If the System.Web.Profile.ProfileInfo.LastActivityDate of a user profile occurs on or before this date and time, the profile is considered inactive.</param>
        /// <returns>The number of profiles in which the last activity date occurred on or before the specified date.</returns>
        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {

            int inactiveProfiles = 0;

            ProfileInfoCollection profiles = GetProfileInfo(authenticationOption, null, userInactiveSinceDate, 0, 0, out inactiveProfiles);

            return inactiveProfiles;
        }

        //Verifies input parameters for page size and page index.
        private static void CheckParameters(int pageIndex, int pageSize)
        {
            if (pageIndex < 1 || pageSize < 1)
                throw new ApplicationException(ERR_INVALID_PARAMETER + " page index.");
        }

        //GetProfileInfo
        //Retrieves a count of profiles and creates a 
        //ProfileInfoCollection from the profile data in the 
        //database. Called by GetAllProfiles, GetAllInactiveProfiles,
        //FindProfilesByUserName, FindInactiveProfilesByUserName, 
        //and GetNumberOfInactiveProfiles.
        //Specifying a pageIndex of 0 retrieves a count of the results only.
        private static ProfileInfoCollection GetProfileInfo(ProfileAuthenticationOption authenticationOption, string usernameToMatch, object userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {

            ProfileInfoCollection profiles = new ProfileInfoCollection();

            totalRecords = 0;

            // Count profiles only.
            if (pageSize == 0)
                return profiles;

            int counter = 0;
            int startIndex = pageSize * (pageIndex - 1);
            int endIndex = startIndex + pageSize - 1;

            DateTime dt = new DateTime(1900, 1, 1);
            if (userInactiveSinceDate != null)
                dt = (DateTime)userInactiveSinceDate;

            /*
            foreach(CustomProfileInfo profile in dal.GetProfileInfo((int)authenticationOption, usernameToMatch, dt, applicationName, out totalRecords)) {
                if(counter >= startIndex) {
                    ProfileInfo p = new ProfileInfo(profile.UserName, profile.IsAnonymous, profile.LastActivityDate, profile.LastUpdatedDate, 0);
                    profiles.Add(p);
                }

                if(counter >= endIndex) {
                    break;
                }

                counter++;
            }
            */
            return profiles;
        }
    }
}

É assim que eu uso no controlador:

    public ActionResult AddTyreToCart(CartViewModel model)
    {

        string profile = Request.IsAuthenticated ? Request.AnonymousID : User.Identity.Name;

    }

Eu gostaria de depurar:Como dois usuários que fornecem cookies diferentes podem obter o mesmo ID de perfil?

EDITAR

Aqui está o código para getuniqueid

public int GetUniqueID(string userName, bool isAuthenticated, bool ignoreAuthenticationType, string appName)
{

  SqlParameter[] parms = {
            new SqlParameter("@Username", SqlDbType.VarChar, 256),
            new SqlParameter("@ApplicationName", SqlDbType.VarChar, 256)};
  parms[0].Value = userName;
  parms[1].Value = appName;

  if (!ignoreAuthenticationType)
  {
    Array.Resize(ref parms, parms.Length + 1);
    parms[2] = new SqlParameter("@IsAnonymous", SqlDbType.Bit) { Value = !isAuthenticated };
  }

  int userID;

  object retVal = null;
  retVal = SqlHelper.ExecuteScalar(ConfigurationManager.ConnectionStrings["SQLOrderB2CConnString"].ConnectionString, CommandType.StoredProcedure, "getProfileUniqueID", parms);

  if (retVal == null)
    userID = CreateProfileForUser(userName, isAuthenticated, appName);
  else
    userID = Convert.ToInt32(retVal);
  return userID;
}

E este é o SP:

CREATE  PROCEDURE [dbo].[getProfileUniqueID]

@Username VarChar( 256),
@ApplicationName VarChar( 256),
@IsAnonymous bit = null
AS
BEGIN

    SET NOCOUNT ON;
/*
[getProfileUniqueID]

created 
08.07.2009  mf

Retrive unique id for current user

*/
SELECT UniqueID FROM dbo.Profiles WHERE Username = @Username 
AND ApplicationName = @ApplicationName
AND IsAnonymous = @IsAnonymous or @IsAnonymous = null

END

Nenhuma solução correta

Outras dicas

Eu não olhei para isso em profundidade, mas uma coisa pulava para mim.

Na sua mudança de cláusula

@IsAnonymous = null

para

@IsAnonymous IS NULL

O que você quer que aconteça quando @isanonymous é nulo? Pode ser necessário adicionar alguns parênteses à cláusula WHERE.

SELECT UniqueID FROM dbo.Profiles 
WHERE Username = @Username 
    AND ApplicationName = @ApplicationName
    AND (IsAnonymous = @IsAnonymous OR @IsAnonymous IS NULL)

Vocês dois usuários que receberam os mesmos dados de perfil? Se sim, comece aí. Eu os passaria pelo PROC armazenado primeiro. Seria fácil e rápido de fazer.

Este é um tipo de problema muito difícil para solucionar problemas. Tivemos um problema semelhante em um aplicativo ASP.NET (não MVC). Eu sugiro que você possa começar definindo um cookie separado para identificar o usuário, ignorando completamente o sistema de perfil do ASP.NET. Você pode verificar se a identidade nesse cookie corresponde à identidade no perfil. Caso contrário, você pode 1) registrar o usuário para que pelo menos eles não tenham acesso aos dados de outra pessoa e 2) reunir algumas informações de diagnóstico - os detalhes completos da solicitação HTTP seria um início. Se isso não estabelecer nenhum tipo de padrão, você poderá começar a registrar todas as solicitações HTTP do usuário para ver se existe um padrão no histórico de solicitações que o ajuda a reproduzir o problema.

No nosso caso, a questão acabou sendo um mecanismo bobo de armazenamento caseiro. O aplicativo tentaria cache arquivos estáticos (por exemplo, imagens) no ASP.NET e os cookies foram armazenados em cache com eles. Sob carga pesada, um usuário às vezes carrega uma imagem com os cookies de outro usuário e assumia a identidade do outro usuário. Seu caso pode ser completamente diferente, mas isso pode lhe dar alguma pista do tipo de coisa a procurar.

As fontes fornecidas parecem estar corretas, mas não posso fazer uma declaração profunda sem ter todo o código-fonte correspondente (por exemplo.todos os métodos usados ​​da classe B2CShop.DAL.UserRepository), talvez até o esquema do banco de dados.

Primeiro seria verificar se talvez os dados no banco de dados estejam corrompidos, ou seja, algum usuário pode literalmente possuir o mesmo ID exclusivo ou a mesma combinação de nome de usuário/aplicativo/isanônimo.Isto pode ser excluído se uniqueid for uma chave primária.

Sempre que esse tipo de problema acontece...Eu vi o seguinte como as causas ...

  1. Cache
  2. Variáveis ​​estáticas

Você pode tentar escrever este código sem variáveis ​​estáticas e verificar se o problema foi resolvido?

Atenciosamente, Rahul

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top