1. Upgrade all Fusion package references to v6.1+.
2. Replace all references to ActualLab.Fusion.Client
to ActualLab.Fusion
- there is no separate client assembly in v6.1+, ActualLab.Fusion.dll
contains the client.
3. If you are using Fusion authentication (e.g. IAuth
, User
, etc. - in fact, almost everything related to Fusion authentication except Session
), reference:
ActualLab.Fusion.Ext.Contracts
- from your contracts / client-side projectsActualLab.Fusion.Ext.Services
- from your server-side projects.
4. If you are using some projects declaring just IXxxClientDef
types, remove these projects.
5. Any project that declares compute or command services must reference ActualLab.Generators
.
6. Any project that declares [MemoryPackable]
types must reference MemoryPack.Generator
.
1. Any compute service should implement IComputeService
, any command service should implement ICommandService
.
These interfaces are just tagging ones, i.e. there are no any methods. ActualLab.Generators
analyzers require them to generate proxies for such services.
Most likely you declare interfaces for any of such services to consume them on the client - and in this case the interface must be inherited from either IComputeService
or ICommandService
.
2. Decorate any non-primitive type which "travels" between the client & server with MemoryPack
serialization attributes and make them partial
. E.g. if you had:
// In pre-v6.1 such commands are typically nested into IXxxService
public record PostCommand(string Name, string Text) : ICommand<Unit>;
You should convert it to ~ this:
// 1. MemoryPack doesn't support nested types, so it has to be moved out of IXxxService; Rider/ReSharper has a refactoring for this, as for VS.NET, I am not sure.
// 2. All `[MemoryPackable]` types must be declared as `partial`
// 3. [MemoryPackable(GenerateType.VersionTolerant)] requires you to explicitly mark every serializable member with [MemoryPackOrder]
// 4. [DataContract] and [DataMember] are optional - you may want to have them if you end up using e.g. MessagePack serializer
[DataContract, MemoryPackable(GenerateType.VersionTolerant)]
public partial record Chat_Post(
[property: DataMember, MemoryPackOrder(0)] string Name,
[property: DataMember, MemoryPackOrder(1)] string Text
) : ICommand<Unit>;
Note that any assembly which declares such types should reference MemoryPack.Generator
package.
More details on MemoryPack
serializer: https://github.com/Cysharp/MemoryPack
- Search for e.g.
[BasePath
or[Get(
to find allIXxxClientDef
-s
Replace the following complete words:
AddComputeService
->AddService
AddCommandService
->AddService
LatestNonErrorValue
->LastNonErrorValue
LatestNonErrorComputed
->LastNonErrorComputed
Session.Null
->null!
ISessionProvider
->ISessionResolver
+ maybe rename related variables/properties.ISessionResolver
is the same asISessionProvider
in pre-v6.1, and oldISessionResolver
is goneBlazorModeController.IsServerSideBlazor(HttpContext)
->BlazorModeEndpoint.IsBlazorServer(HttpContext)
MapFusionWebSocketServer
->MapRpcWebSocketServer
MapFusionBlazorSwitch
->MapFusionBlazorMode
AddBackendStatus
->AddRpcPeerStateMonitor
StateHasChangedAsync
->NotifyStateHasChanged
1. Remove old Fusion server setup logic.
2. Add the new one:
var fusion = services.AddFusion(RpcServiceMode.Server, true);
var fusionServer = fusion.AddWebServer();
The first line tells that any FusionBuilder
(including fusion
) we'll use further must publish any service registered via AddService
call via ActualLab.Rpc
- in other words, it "turns" any AddService
call to AddServer
call further.
The second call registers an RPC endpoint (/rpc/ws
) and maps it to a WebSocket server from ActualLab.Rpc.Server
package.
3. If you're using Fusion authentication, configure its endpoints like this:
fusionServer.ConfigureAuthEndpoint(_ => new() {
DefaultSignInScheme = MicrosoftAccountDefaults.AuthenticationScheme,
SignInPropertiesBuilder = (_, properties) => {
properties.IsPersistent = true;
}
});
fusionServer.ConfigureServerAuthHelper(_ => new() {
NameClaimKeys = Array.Empty<string>(),
});
4. If you're using ASP.NET Core Minimal API, map additional endpoints:
endpoints.MapRpcWebSocketServer(); // Absolutely necessary
endpoints.MapFusionAuth(); // Optional - maps /signIn & /signOut endpoints
endpoints.MapFusionBlazorMode(); // Optional - maps /fusion/blazorMode/{isBlazorServer}
And if you prefer to use controllers for Fusion authentication & Blazor mode switch, add this instead:
fusionServer.AddMvc().AddControllers();
For the note, these controllers now call the same services as endpoints, i.e. performance-wise endpoints are slightly better.
5. If you're using DbAuthService
, its server-side builder is now invoked differently.
It used to be called like this:
db.AddAuthentication<...>();
And now it has to be:
fusion.AddDbAuthService<AppDbContext, ...>();
6. If you're using fusionAuth.js
script to open sign-in/sign-out popup in Blazor, update its location:
- Search for
_content/ActualLab.Fusion.Blazor/scripts/fusionAuth.js
- most likely you'll find it in_Host.cshtml
- Replace it with
_content/ActualLab.Fusion.Blazor.Authentication/scripts/fusionAuth.js
As you might notice, this also means you need to reference ActualLab.Fusion.Blazor.Authentication
package.
1. You must remove the old RestEase client. Search for fusion.AddRestEaseClient(
and remove this call + any uses of its output except the ones w/ AddReplicaService
call.
E.g. if you had this code:
var fusionClient = fusion.AddRestEaseClient();
fusionClient.ConfigureHttpClient((c, name, options) => {
options.HttpClientActions.Add(client => client.BaseAddress = apiBaseUri);
});
fusionClient.ConfigureWebSocketChannel(c => new () {
BaseUri = baseUri,
});
// Registering replica service
fusionClient.AddReplicaService<ICounterService, ICounterClientDef>();
Leave just this (we'll update it later):
fusionClient.AddReplicaService<ICounterService, ICounterClientDef>();
Finally, replace fusionClient.AddReplicaService<TInterface, TClientDef>()
calls with fusion.AddClient<TInterface>()
.
You can do this in two steps:
- Replace
fusionClient.AddReplicaService
withfusion.AddClient
- Remove the extra argument.
2. Add new ActualLab.Rpc
WebSocket client:
fusion.Rpc.AddWebSocketClient(builder.HostEnvironment.BaseAddress);
3. If you are using Fusion authentication, add IAuth
service client:
fusion.AddAuthClient();
1. If you're using Fusion authentication, reference ActualLab.Fusion.Blazor.Authentication
package. The authentication components are optional now, so they're extracted to dedicated assemblies.
2. To add Fusion's Blazor components / integrations, run the following calls:
var fusionBlazor = fusion.AddBlazor();
// Optional calls:
// If you're going to use Fusion's AuthenticationStateProvider, add the following call:
fusionBlazor.AddAuthentication(); // Must go somewhere after services.AddServerSideBlazor() on the server side!
// If you'd like to automatically bump up SessionInfo.LastSeenAt while the client uses Session:
fusionBlazor.AddPresenceReporter();
These calls must be executed:
- On the client side, if you use just WASM client
- On the server side, if you use Blazor Server
- On both sides, if you use both.
3. If you are using <CascadingAuthState>
, you can make it to automatically start presence reporter like this now:
<CascadingAuthState UsePresenceReporter="true">
...
</CascadingAuthState>
1. Authentication and other optional extensions were moved to ActualLab.Fusion.Ext.Contracts
and ActualLab.Fusion.Ext.Services
packages - with corresponding namespace changes. So most likely you'll need to replace:
using ActualLab.Fusion.EntityFramework.Authentication
tousing ActualLab.Fusion.Authentication
; on the server side, you'll also need to addusing ActualLab.Fusion.Authentication.Services
.using ActualLab.Fusion.EntityFramework.Extensions
(if you are usingIKeyValueStore
, etc.) tousing ActualLab.Fusion.Extensions
; on the server side, you'll also need to addusing ActualLab.Fusion.Extensions.Services
.
2. TaskSource<T>
type is gone (its performance was arguable). Use TaskCompletionSource<T>
instead. You can use TaskCompletionSourceExt.New
instead of TaskSource.New
- it behaves identically, but returns similarly configured TaskCompletionSource
instead of TaskSource
.