Skip to content
Merged
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
116 changes: 111 additions & 5 deletions docs/Upgrading to CSLA 10.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ If you are upgrading from a version of CSLA prior to 8, you should review the [U

## Platform Support

TBD
CSLA 10 continues to support .NET Framework 4.6.2 and later, as well as modern .NET versions. CSLA 10 adds support for .NET 10.

## RevalidatingInterceptor

The constructor has changed and now expects an `IOptions<RevalidatingInterceptorOptions>` instance. With this new options object it is now possible to skip the revalidation of business rules during a `Delete` operation.
To configure the new options we are using the .Net [Options pattern](https://learn.microsoft.com/en-us/dotnet/core/extensions/options).

```csharp
services.Configure<RevalidatingInterceptorOptions>(opts =>
{
Expand All @@ -24,26 +25,30 @@ services.Configure<RevalidatingInterceptorOptions>(opts =>
## New exception handler for asynchronous rules
A new API is added to make it possible to handle exceptions thrown by asynchronous rules.
The new interface to implement is `Csla.Rules.IUnhandledAsyncRuleExceptionHandler` which has two methods
* `bool CanHandle(Exception, IBusinessRuleBase)`
* to decide whether this exception should be handled or not

* `bool CanHandle(Exception, IBusinessRuleBase)`
* to decide whether this exception should be handled or not
* `ValueTask Handle(Exception, IBusinessRuleBase, IRuleContext)`
* to handle the exception when `CanHandle(...) == true`
* to handle the exception when `CanHandle(...) == true`

With these methods you can now decide whether to handle the exception and how or let the exception be unobserved bubble up and potentially cause a crash.

You can register your implementation in two ways

* Just add the implementation to your service collection `services.AddScoped<IUnhandledAsyncRuleExceptionHandler, YourImplementation>()`
* Note: This has to be registered _after_ csla is added to the service collection.
* Use `services.AddCsla(o => o.UseUnhandledAsyncRuleExceptionHandler<YourImplementation>());`. The handler is registered as scoped.

The _default_ is still no handling of any exception thrown in an asynchronous rule.

## `IDataPortal` / `IChildDataPortal` breaking changes

Both interfaces `IDataPortal` and `IChildDataPortal` got the following changes to improve trimming support:
* Returning `ICslaObject`instead of `object`.
* `Update`/`Execute` now expect an `ICslaObject` parameter instead of `object`.

## `InjectAttribute` - AllowNull addition

The `InjectAttribute` got a new property called `AllowNull`. This property controls whether csla will use `GetService` or `GetRequiredService`.
With `AllowNull == true` means it's using `GetService` which can return a `null` for a requested object.
With `AllowNull == false` means it's using `GetRequiredService` which can not return `null` and will cause an exception.
Expand Down Expand Up @@ -128,8 +133,109 @@ Supporting nullable types means that some APIs have changed to support nullable
* `UpdateRequest` now uses `[AutoSerializable]` to auto implement `IMobileObject` instead of inheriting from `ReadOnlyBase`.


## `ViewModel<T>.SaveAsync` and `CslaDataProvider.Refresh` return `Task`

The `ViewModel<T>.SaveAsync(object sender, ExecuteEventArgs e)` method and `CslaDataProvider.Refresh<T>(Func<Task<T>> factory)` method now return `Task` instead of `async void`. This is a breaking change for any code that calls these methods directly.

If you were calling these methods without awaiting them, you will now need to handle the returned `Task` appropriately:

```csharp
// Before (async void - fire and forget)
viewModel.SaveAsync(sender, e);

// After (returns Task - must be handled)
await viewModel.SaveAsync(sender, e);
// or if you truly want fire-and-forget behavior:
_ = viewModel.SaveAsync(sender, e);
```

## OpenTelemetry Instrumentation

CSLA 10 adds OpenTelemetry instrumentation for the data portal. A new `OpenTelemetryDashboard` class provides metrics for data portal operations including total calls, completed calls, failed calls, and call duration.

To enable OpenTelemetry metrics, register the dashboard:

```csharp
services.AddCsla(o => o.DataPortal(dp =>
dp.RegisterDashboard<OpenTelemetryDashboard>()));
```

The metrics integrate with standard OpenTelemetry consumers such as Prometheus, Grafana, Azure Monitor, and .NET Aspire dashboards.

## Virtual `Deserialized` Method

A new `protected virtual void Deserialized()` method has been added to `BusinessBase`, `ExtendedBindingList`, and `ObservableBindingList`. This method is called after deserialization completes and provides an extension point for custom post-deserialization logic.

```csharp
public class MyBusinessObject : BusinessBase<MyBusinessObject>
{
protected override void Deserialized()
{
base.Deserialized();
// Custom post-deserialization logic here
}
}
```

## `IMobileObjectMetastate` Interface

A new `IMobileObjectMetastate` interface has been added to `Csla.Serialization.Mobile`. This interface is intended for developers creating custom serializers as an alternative to `MobileFormatter`.

The interface defines two methods:
* `byte[] GetMetastate()` - Gets lightweight serialization of field values (metastate) without child object references
* `void SetMetastate(byte[] metastate)` - Sets the metastate from a byte array

This interface is implemented on `MobileObject`, `MobileBindingList`, and `ReadOnlyListBase`. The metastate is intended for transitory data serialization, not long-term storage.

## Binary Serialization for Metastate

The internal serialization of metastate data now uses binary serialization instead of JSON. This provides improved performance for data portal operations. Since CSLA requires the same version on both ends of a network connection, this change is transparent to most applications.

## Principal Caching Removed

`ApplicationContextManager.GetUser()` no longer caches the current principal. It now always retrieves the principal from `Thread.CurrentPrincipal`. This improves behavior in multi-threaded scenarios and prevents stale principal references.

If your code relied on the previous caching behavior, you may need to review your authorization logic.

## `TransactionIsolationLevel.Snapshot`

A new `Snapshot` option has been added to the `TransactionIsolationLevel` enum. This allows use of snapshot isolation when using the `Transactional` attribute:

```csharp
[Transactional(TransactionIsolationLevel.Snapshot)]
private void DataPortal_Update()
{
// Update logic with snapshot isolation
}
```

## `FriendlyName` Property on XAML `PropertyInfo`

The `Csla.Xaml.PropertyInfo` component now includes a `FriendlyName` property that can be used to display a user-friendly property name in WPF/XAML applications.

## `RuleContextModes` for Rule Execution Control

A new `RuleContextModes` enum has been added to provide control over when rules execute. The `RuleContext` now includes an `ExecuteContext` property with the following flags:
* `Any` - Rule executes in any context
* `CheckRules` - Rule executes during CheckRules calls
* `CheckObjectRules` - Rule executes during CheckObjectRules calls
* `PropertyChanged` - Rule executes when the property changes
* `AsAffectedProperty` - Rule executes as an affected property

## `ScanForDataAnnotations` Configuration Option

A new configuration option `CslaOptions.ScanForDataAnnotations(bool flag)` allows disabling the automatic scanning for DataAnnotations attributes on business objects.

```csharp
services.AddCsla(o => o.ScanForDataAnnotations(false));
```

> **Caution:** Setting this to `false` completely disables DataAnnotations attribute support within CSLA. Only use this option if you are certain your application does not use DataAnnotations attributes for validation and you need the performance benefit of skipping the attribute scan.

## Breaking changes

* `Csla.Server.DataPortal` constructor changed.
* Removed unused parameters: `IDataPortalActivator activator`, `IDataPortalExceptionInspector exceptionInspector`.
* `Csla.Rules.BusinessRules` constructor changed.
* New parameter `IUnhandledAsyncRuleExceptionHandler` added to support the new asynchronous rule exception handling.
* New parameter `IUnhandledAsyncRuleExceptionHandler` added to support the new asynchronous rule exception handling.