Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ CSLA0010 | Design | Warning | FindOperationsWithNonSerializableArgumentsAnalyzer
CSLA0011 | Usage | Error | FindBusinessObjectCreationAnalyzer
CSLA0012 | Design | Error | FindOperationsWithIncorrectReturnTypesAnalyzer
CSLA0013 | Usage | Warning | DoesChildOperationHaveRunLocalAnalyzer
CSLA0014 | Usage | Info | DoesOperationHaveAttributeAnalyzer
CSLA0014 | Usage | Warning | DoesOperationHaveAttributeAnalyzer
CSLA0015 | Usage | Error | EvaluateOperationAttributeUsageAnalyzer
CSLA0016 | Usage | Error | AsynchronousBusinessRuleInheritingFromBusinessRuleAnalyzer
CSLA0017 | Usage | Warning | BusinessRuleDoesNotUseAddMethodsOnContextAnalyzer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed class DoesOperationHaveAttributeAnalyzer
new(
Constants.AnalyzerIdentifiers.DoesOperationHaveAttribute, DoesOperationHaveAttributeAnalyzerConstants.Title,
DoesOperationHaveAttributeAnalyzerConstants.Message, Constants.Categories.Usage,
DiagnosticSeverity.Info, true,
DiagnosticSeverity.Warning, true,
helpLinkUri: HelpUrlBuilder.Build(
Constants.AnalyzerIdentifiers.DoesOperationHaveAttribute, nameof(DoesOperationHaveAttributeAnalyzer)));

Expand Down Expand Up @@ -52,7 +52,9 @@ private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
{
var qualification = methodSymbol.IsDataPortalOperation();

if(qualification.ByNamingConvention && !qualification.ByAttribute)
// ByAttribute includes attributes inherited from an overridden method
// (such as BusinessBase.Child_Create), which the data portal still calls.
if (qualification.ByNamingConvention && !qualification.ByAttribute)
{
context.ReportDiagnostic(Diagnostic.Create(
operationAttributeRule, methodSymbol.Locations[0]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ public DataPortalOperationQualification Combine(DataPortalOperationQualification
qualification.ByAttribute | ByAttribute);

/// <summary>
///
/// The data portal only invokes methods that have an operation attribute,
/// so a method qualifies as an operation only by attribute.
/// <see cref="ByNamingConvention"/> is used only to find methods that
/// look like legacy operations but are missing their attribute.
/// </summary>
public static implicit operator bool(DataPortalOperationQualification qualification) =>
qualification.ByAttribute | qualification.ByNamingConvention;
qualification.ByAttribute;
Comment thread
rockfordlhotka marked this conversation as resolved.

/// <summary>
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ internal static DataPortalOperationQualification IsRootDataPortalOperation(this
@this.Name == CslaMemberConstants.Operations.DataPortalDelete ||
@this.Name == CslaMemberConstants.Operations.DataPortalDeleteSelf ||
@this.Name == CslaMemberConstants.Operations.DataPortalExecute;
var byAttribute = @this.GetAttributes().Any(_ => _.AttributeClass.IsDataPortalRootOperationAttribute());
var byAttribute = @this.HasOperationAttribute(_ => _.IsDataPortalRootOperationAttribute());
return new DataPortalOperationQualification(byNamingConvention, byAttribute);
}
}
Expand All @@ -73,11 +73,26 @@ internal static DataPortalOperationQualification IsChildDataPortalOperation(this
@this.Name == CslaMemberConstants.Operations.ChildUpdate ||
@this.Name == CslaMemberConstants.Operations.ChildDeleteSelf ||
@this.Name == CslaMemberConstants.Operations.ChildExecute;
var byAttribute = @this.GetAttributes().Any(_ => _.AttributeClass.IsDataPortalChildOperationAttribute());
var byAttribute = @this.HasOperationAttribute(_ => _.IsDataPortalChildOperationAttribute());
return new DataPortalOperationQualification(byNamingConvention, byAttribute);
}
}

// The data portal reads operation attributes with inherit: true, so an
// override (such as of BusinessBase.Child_Create) inherits the attribute
// of the method it overrides.
private static bool HasOperationAttribute(this IMethodSymbol @this, Func<INamedTypeSymbol?, bool> isOperationAttribute)
{
for (var method = @this; method is not null; method = method.OverriddenMethod)
{
if (method.GetAttributes().Any(_ => isOperationAttribute(_.AttributeClass)))
{
return true;
}
}
return false;
}

internal static CslaOperationQualification IsAddObjectAuthorizationRulesOperation(this IMethodSymbol @this)
{
if (@this is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
<value>Find Operations That Do Not Have an Operation Attribute</value>
</data>
<data name="DoesOperationHaveAttribute_Message" xml:space="preserve">
<value>Operations should have the appropriate operation attribute</value>
<value>This method is named like a data portal operation but has no operation attribute, so the data portal never calls it. Add the operation attribute.</value>
</data>
<data name="Shared_AddAttributeAndUsingDescription" xml:space="preserve">
<value>Add attribute and using statement</value>
Expand Down
9 changes: 5 additions & 4 deletions Source/Csla/BusinessBindingListBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@ public override bool IsBusy
/// with default values.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[CreateChild]
protected virtual void Child_Create()
{ /* do nothing - list self-initializes */ }

Expand Down Expand Up @@ -1128,7 +1129,7 @@ public async Task SaveAndMergeAsync()

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_xyz method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
Expand All @@ -1138,7 +1139,7 @@ protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_xyz method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
Expand All @@ -1159,7 +1160,7 @@ protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, E

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_XYZ method.
/// requested child data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
Expand All @@ -1169,7 +1170,7 @@ protected virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_XYZ method.
/// requested child data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
Expand Down
9 changes: 5 additions & 4 deletions Source/Csla/BusinessListBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,7 @@ public override bool IsBusy
/// with default values.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[CreateChild]
protected virtual void Child_Create()
{ /* do nothing - list self-initializes */ }

Expand Down Expand Up @@ -1155,7 +1156,7 @@ public async Task SaveAndMergeAsync()

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_xyz method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand All @@ -1164,7 +1165,7 @@ protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_xyz method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand All @@ -1183,7 +1184,7 @@ protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, E

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_XYZ method.
/// requested child data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand All @@ -1192,7 +1193,7 @@ protected virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_XYZ method.
/// requested child data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand Down
42 changes: 5 additions & 37 deletions Source/Csla/CommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ namespace Csla
/// type of stateless, atomic call to the server instead.
/// </para><para>
/// To implement a command object, inherit from CommandBase and
/// override the DataPortal_Execute method. In this method you can
/// implement any server-side code as required.
/// implement a method marked with the <see cref="ExecuteAttribute"/>.
/// In this method you can implement any server-side code as required.
/// </para><para>
/// To pass data to/from the server, use instance variables within
/// the command object itself. The command object is instantiated on
/// the client, and is passed by value to the server where the
/// DataPortal_Execute method is invoked. The command object is then
/// <see cref="ExecuteAttribute"/> method is invoked. The command object is then
/// returned to the client by value.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -75,41 +75,9 @@ protected virtual void Initialize()

#region Data Access

[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private void DataPortal_Create(object criteria)
{
throw new NotSupportedException(Resources.CreateNotSupportedException);
}

[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private void DataPortal_Fetch(object criteria)
{
throw new NotSupportedException(Resources.FetchNotSupportedException);
}

[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private void DataPortal_Update()
{
throw new NotSupportedException(Resources.UpdateNotSupportedException);
}

[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[Delete]
private void DataPortal_Delete(object criteria)
{
throw new NotSupportedException(Resources.DeleteNotSupportedException);
}

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_xyz method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
Expand All @@ -121,7 +89,7 @@ protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_xyz method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
Expand Down
7 changes: 0 additions & 7 deletions Source/Csla/Configuration/Fluent/DataPortalOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,6 @@ public string VersionRoutingTag
/// </summary>
internal DataPortalServerOptions DataPortalServerOptions { get; }

/// <summary>
/// Gets or sets a value indicating whether legacy DataPortal_XYZ and
/// Child_XYZ method names are used as a fallback when no attributed
/// data portal operation methods are found. Default is true.
/// </summary>
public bool UseLegacyOperationMethods { get; set; } = true;

internal CslaOptions CslaOptions { get; }
}
}
33 changes: 18 additions & 15 deletions Source/Csla/Core/BusinessBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ protected virtual void SetParent(IParent? parent)
/// <remarks>
/// <para>
/// Newly created objects are marked new by default. You should call
/// this method in the implementation of DataPortal_Update when the
/// object is deleted (due to being marked for deletion) to indicate
/// this method in the implementation of your <see cref="UpdateAttribute"/>
/// or <see cref="DeleteSelfAttribute"/> method when the object is deleted (due to being marked for deletion) to indicate
/// that the object no longer reflects data in the database.
/// </para><para>
/// If you override this method, make sure to call the base
Expand All @@ -263,12 +263,12 @@ protected virtual void MarkNew()
/// </summary>
/// <remarks>
/// <para>
/// You should call this method in the implementation of
/// DataPortal_Fetch to indicate that an existing object has been
/// You should call this method in the implementation of your
/// <see cref="FetchAttribute"/> method to indicate that an existing object has been
/// successfully retrieved from the database.
/// </para><para>
/// You should call this method in the implementation of
/// DataPortal_Update to indicate that a new object has been successfully
/// You should call this method in the implementation of your
/// <see cref="InsertAttribute"/> method to indicate that a new object has been successfully
/// inserted into the database.
/// </para><para>
/// If you override this method, make sure to call the base
Expand Down Expand Up @@ -1312,7 +1312,7 @@ public virtual Task WaitForIdle(CancellationToken ct)

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_XYZ method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand All @@ -1321,7 +1321,7 @@ protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_XYZ method.
/// requested data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand All @@ -1339,22 +1339,25 @@ protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, E
{ }

/// <summary>
/// Override this method to load a new business object with default
/// values from the database.
/// Initializes a new child object with default values
/// and checks its business rules.
/// </summary>
/// <remarks>
/// Normally you will overload this method to accept a strongly-typed
/// criteria parameter, rather than overriding the method with a
/// loosely-typed criteria parameter.
/// The child data portal calls this method when a create child
/// operation has no criteria and the business class doesn't
/// declare a better matching <see cref="CreateChildAttribute"/>
/// method. Normally you will implement your own method marked with
/// <see cref="CreateChildAttribute"/>, rather than overriding this one.
/// </remarks>
[CreateChild]
protected virtual void Child_Create()
{
BusinessRules.CheckRules();
}

/// <summary>
/// Called by the server-side DataPortal prior to calling the
/// requested DataPortal_XYZ method.
/// requested child data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand All @@ -1363,7 +1366,7 @@ protected virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)

/// <summary>
/// Called by the server-side DataPortal after calling the
/// requested DataPortal_XYZ method.
/// requested child data portal operation method.
/// </summary>
/// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
Expand Down
2 changes: 1 addition & 1 deletion Source/Csla/DataPortalT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ private async Task<T> DoUpdateAsync(T obj, bool isSync, CancellationToken ct = d
if (factoryType != null)
method = Server.DataPortalMethodCache.GetMethodInfo(factoryType, factoryInfo.DeleteMethodName, [obj]);
}
// must check the same authorization rules as for DataPortal_XYZ methods
// must check the same authorization rules as for data portal operation methods
else if (bbase.IsNew)
{
if (!await Rules.BusinessRules.HasPermissionAsync(_applicationContext, Rules.AuthorizationActions.CreateObject, obj, ct))
Expand Down
Loading
Loading