CSLA 3.6.2 Bug? - DataPortal.Delete Delete Exception.

CSLA 3.6.2 Bug? - DataPortal.Delete Delete Exception.

Old forum URL: forums.lhotka.net/forums/t/6604.aspx


bniemyjski posted on Friday, March 13, 2009

Hello,

"The exception indicates the problem is in the authorization subsystem, and so it probably has nothing to do with your criteria class at all. I don’t know the cause of the exception, as I haven’t encountered a case where the delete authorization check failed like this." - Rocky

I have snippets of the classes in question...

I have modeled the criteria class off of CriteriaBase

Serializable]

     public partial class ItemCriteria : CriteriaBase

     {

 

and the Item class like this:


[Serializable]
    public partial class Item : BusinessBase< Item >
    {


        #region Authorization Rules
       
        protected override void AddAuthorizationRules()
        {
            // TODO: add authorization rules
            //AuthorizationRules.AllowWrite(NameProperty, "Role");
        }
       
        private static void AddObjectAuthorizationRules()
        {
            // TODO: add authorization rules
            //AuthorizationRules.AllowEdit(typeof(Item), "Role");
        }
       
        #endregion



--------------------------



Item.DeleteItem("EST-85");

 

Calls

 

public static void DeleteItem(string itemId)

{

                DataPortal.Delete(new ItemCriteria(itemId));

}

 

which throws:

 

 

 

Exception ("Value cannot be null.\r\nParameter name: key)

 

Stack Trace

 

 

   at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)

   at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)

   at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)

   at Csla.Security.ObjectAuthorizationRules.GetRoles(Type objectType) in C:\Users\Administrator\Desktop\CSLA3.6.1\Source\CSLA\Security\ObjectAuthorizationRules.cs:line 19

   at Csla.Security.AuthorizationRules.GetAllowDeleteRoles(Type objectType) in C:\Users\Administrator\Desktop\CSLA3.6.1\Source\CSLA\Security\AuthorizationRules.cs:line 749

   at Csla.Security.AuthorizationRules.CanDeleteObject(Type objectType) in C:\Users\Administrator\Desktop\CSLA3.6.1\Source\CSLA\Security\AuthorizationRules.cs:line 858

   at Csla.DataPortal.Delete(Type objectType, Object criteria) in C:\Users\Administrator\Desktop\CSLA3.6.1\Source\CSLA\DataPortal.cs:line 562

   at Csla.DataPortal.Delete(Object criteria) in C:\Users\Administrator\Desktop\CSLA3.6.1\Source\CSLA\DataPortal.cs:line 505

   at PetShop.Business.Item.DeleteItem(String itemId) in C:\Users\Administrator\Documents\CodeSmith\Templates\PetShop\PetShop.Business\Item.Generated.cs:line 154

   at PetShop.UI.Program.Main(String[] args) in C:\Users\Administrator\Documents\CodeSmith\Templates\PetShop\PetShop.UI\Program.cs:line 11

   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)

   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

   at System.Threading.ThreadHelper.ThreadStart()

If anyone has an idea on how to fix this it would be sweet. I have wrote unit tests that reproduce this on the BO, the DAL tests execute as expected.

Thanks
-Blake Niemyjski

RockfordLhotka replied on Friday, March 13, 2009

Can you show more of your criteria class? At least the constructor(s)?

bniemyjski replied on Friday, March 13, 2009

#region using declarations

using System;
using System.Collections.Generic;
using System.Data.SqlClient;

using Csla;

#endregion

namespace PetShop.Business
{
    [Serializable]
    public partial class AccountCriteria : CriteriaBase
    {
        #region Private Read-Only Members
        
        private readonly Dictionary<string, object> _bag = new Dictionary<string, object>();
        
        #endregion
        
        #region Constructors

        public AccountCriteria(){}

        public AccountCriteria(int accountID)
        {
            AccountID = accountID;
        }
        
        #endregion
        
        #region Public Properties
        
        #region Read-Write
        
        public int UniqueID
        {
            get { return GetValue< int >("UniqueID"); }                
            set { _bag["UniqueID"] = value; }
        }
        
        public int AccountID
        {
            get { return GetValue< int >("AccountID"); }                
            set { _bag["AccountID"] = value; }
        }

        #endregion
        
        #region Read-Only
        
        //NOTE: I don't really like this...
        /// <summary>
        /// Returns an array of SqlParameters
        /// </summary>
        public SqlParameter[] Parameters
        {
            get
            {
                List<SqlParameter> parameters = new List<SqlParameter>(_bag.Keys.Count);

                foreach (KeyValuePair<string, object> pair in _bag)
                {
                    parameters.Add(new SqlParameter(string.Format("@p_{0}", pair.Key), pair.Value));
                }

                return parameters.ToArray();
            }
        }
        
        #endregion

        #endregion
        
        #region Private Methods
        
        private T GetValue<T>(string name)
        {
            object value;
            if (_bag.TryGetValue(name, out value))
                return (T) value;
        
            return default(T);
        }
        
        #endregion
        
        #region Public Overriden Methods

        /// <summary>
        /// Returns a where clause for the current Criteria object.
        /// </summary>
        /// <returns>Returns a where clause for the current Criteria object.</returns>
        public override string ToString()
        {
            string columnNames = string.Empty;

            foreach (string columnName in _bag.Keys)
            {
                columnNames += string.Format("[{0}] = @p_{0} AND ", columnName);
            }

            return string.Format("WHERE {0}", columnNames.Remove(columnNames.Length - 5, 5));
        }

        #endregion
    }
}

RockfordLhotka replied on Saturday, March 14, 2009

Try adding the bold code to your constructors. CriteriaBase needs to know the type of business object the criteria is targeting, and the fact that these bits of code are missing might be the issue.

 

       #region Constructors

        public AccountCriteria() : base(typeof(Account) {}

        public AccountCriteria(int accountID) : base(typeof(Account)
        {
            AccountID = accountID;
        }
        
        #endregion

Regarding the SqlParameters property, I agree - that's not ideal.

If it were me, I'd consider that code to be part of the DAL, not the BL. But the criteria class should be in the BL.

To resolve that, I'd add a class in my DAL that has a method that accepts a Dictionary<string, object> as a parameter and returns SqlParameter objects. That way your DAL code can take the Dictionary from the criteria and get the parameters, but you preserve seperation of concerns by keeping SQL code in the DAL, and criteria code in the BL.

bniemyjski replied on Monday, March 16, 2009

Hello,

Thanks that fixed it. I ran into a different issue now however :\.

Thanks
-Blake Niemyjski

Copyright (c) Marimer LLC