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