diff --git a/docs/Upgrading to CSLA 10.md b/docs/Upgrading to CSLA 10.md index 1192f609f3..658fbab285 100644 --- a/docs/Upgrading to CSLA 10.md +++ b/docs/Upgrading to CSLA 10.md @@ -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` 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(opts => { @@ -24,14 +25,16 @@ services.Configure(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()` * Note: This has to be registered _after_ csla is added to the service collection. * Use `services.AddCsla(o => o.UseUnhandledAsyncRuleExceptionHandler());`. The handler is registered as scoped. @@ -39,11 +42,13 @@ You can register your implementation in two ways 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. @@ -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.SaveAsync` and `CslaDataProvider.Refresh` return `Task` + +The `ViewModel.SaveAsync(object sender, ExecuteEventArgs e)` method and `CslaDataProvider.Refresh(Func> 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())); +``` + +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 +{ + 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. \ No newline at end of file + * New parameter `IUnhandledAsyncRuleExceptionHandler` added to support the new asynchronous rule exception handling. + \ No newline at end of file