Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrating .NET 7 to 8 with gRPC - The antiforgery token could not be decrypted #58059

Closed
1 task done
japtar10101 opened this issue Sep 24, 2024 · 4 comments
Closed
1 task done
Labels
area-blazor Includes: Blazor, Razor Components area-grpc Includes: GRPC wire-up, templates

Comments

@japtar10101
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When upgrading a working .NET 7 project using gRPC service to .NET 8, following the Update a Blazor WebAssembly app guide, running the code under Docker causes the following error below:

fail: Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery[7]
      An exception was thrown while deserializing the token.
      Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.
       ---> System.Security.Cryptography.CryptographicException: The key {0012099f-f1c0-45ee-8947-56cf72c7ce53} was not found in the key ring. For more information go to https://aka.ms/aspnet/dataprotectionwarning
         at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
         at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
         at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
         --- End of inner exception stack trace ---
         at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
         at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)

Some extra details:

  • The .NET 8 version of the project does run fine under Visual Studio 2022, Debug config.
  • According to my colleague, they were able to get a similar result with dotnet TestGrpc7.Server.dll, so we believe Docker isn't the source of the problem
  • The gRPC interface has a function returning a Task<Dictionary<string, string>>, which seems to be the source of the problem (see the browser console error below). I haven't confirmed whether it's a gRPC package issue, or whether it's related to Breaking Changes: Custom marshallers require additional members.
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: TypeInitialization_Type, DefaultProxyCache`1
System.TypeInitializationException: TypeInitialization_Type, DefaultProxyCache`1
 ---> System.Reflection.TargetInvocationException: Arg_TargetInvocationException
 ---> System.InvalidOperationException: No marshaller available for System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
   at ProtoBuf.Grpc.Internal.MarshallerCache.<GetMarshaller>g__Throw|5_0[Dictionary`2]()
   at ProtoBuf.Grpc.Internal.MarshallerCache.GetMarshaller[Dictionary`2]()
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object , BindingFlags )
   Exception_EndOfInnerExceptionStack
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object , BindingFlags )
   at System.Reflection.RuntimeMethodInfo.Invoke(Object , BindingFlags , Binder , Object[] , CultureInfo )
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at ProtoBuf.Grpc.Internal.ProxyEmitter.<EmitFactory>g__Marshaller|11_0[IDictionaryService](Type forType, <>c__DisplayClass11_0`1& , <>c__DisplayClass11_1`1& )
   at ProtoBuf.Grpc.Internal.ProxyEmitter.EmitFactory[IDictionaryService](BinderConfiguration binderConfig)
   at ProtoBuf.Grpc.Internal.ProxyEmitter.CreateFactory[IDictionaryService](BinderConfiguration binderConfig)
   at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultProxyCache`1[[TestGrpc7.Client.Services.IDictionaryService, TestGrpc7.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]..cctor()
   Exception_EndOfInnerExceptionStack
   at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultClientFactory.CreateClient[IDictionaryService](CallInvoker channel)
   at Program.<>c.<<Main>$>b__0_1(IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite , RuntimeResolverContext )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite , RuntimeResolverContext )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite , RuntimeResolverContext , ServiceProviderEngineScope , RuntimeResolverLock )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite , RuntimeResolverContext )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite , ServiceProviderEngineScope )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass4_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier , ServiceProviderEngineScope )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type )
   at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass9_0.<CreatePropertyInjector>g__Initialize|1(IServiceProvider serviceProvider, IComponent component)
   at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider , Type , IComponentRenderMode , Nullable`1 )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame[] , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer , RenderBatchBuilder , Int32 , ArrayRange`1 , ArrayRange`1 )
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder , RenderFragment , Exception& )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

Expected Behavior

When running the attached projects in Docker, a web page will show up, indicating the base address of the website (e.g. http://localhost:8080/), as well as a table with key value pairs of:

Keys Values
Hello World
Greetings Nice to meet you, "[base address]"

Steps To Reproduce

The following steps was replicated in Windows 10 Powershell terminal:

  1. Download, then extract the source code below:
  2. At the root of each project (where the Dockerfile is), run: docker build -t test-grpc-7:net8 . This may take a few minutes.
  3. Once the build is finished, run docker run -p 127.0.0.1:8080:8080 test-grpc-7:net8.
  4. Open a web browser (e.g. Chrome or Edge), and navigate to localhost:8080.

For comparison, the net7-grpc-dictionary-bug-1.1.1-net7.zip -- the original .NET 7 version of the same project above -- has been uploaded as well for comparison. Running all the steps above with the .NET 7 version of the project, except changing the version of each docker build from :net8 to :net7, should open the webpage described in the Expected Behavior section without error.

Exceptions (if any)

There are two:

On the Docker console:

fail: Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery[7]
      An exception was thrown while deserializing the token.
      Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.
       ---> System.Security.Cryptography.CryptographicException: The key {0012099f-f1c0-45ee-8947-56cf72c7ce53} was not found in the key ring. For more information go to https://aka.ms/aspnet/dataprotectionwarning
         at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
         at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
         at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
         --- End of inner exception stack trace ---
         at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
         at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)

On the web browser console:

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: TypeInitialization_Type, DefaultProxyCache`1
System.TypeInitializationException: TypeInitialization_Type, DefaultProxyCache`1
 ---> System.Reflection.TargetInvocationException: Arg_TargetInvocationException
 ---> System.InvalidOperationException: No marshaller available for System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
   at ProtoBuf.Grpc.Internal.MarshallerCache.<GetMarshaller>g__Throw|5_0[Dictionary`2]()
   at ProtoBuf.Grpc.Internal.MarshallerCache.GetMarshaller[Dictionary`2]()
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object , BindingFlags )
   Exception_EndOfInnerExceptionStack
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object , BindingFlags )
   at System.Reflection.RuntimeMethodInfo.Invoke(Object , BindingFlags , Binder , Object[] , CultureInfo )
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at ProtoBuf.Grpc.Internal.ProxyEmitter.<EmitFactory>g__Marshaller|11_0[IDictionaryService](Type forType, <>c__DisplayClass11_0`1& , <>c__DisplayClass11_1`1& )
   at ProtoBuf.Grpc.Internal.ProxyEmitter.EmitFactory[IDictionaryService](BinderConfiguration binderConfig)
   at ProtoBuf.Grpc.Internal.ProxyEmitter.CreateFactory[IDictionaryService](BinderConfiguration binderConfig)
   at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultProxyCache`1[[TestGrpc7.Client.Services.IDictionaryService, TestGrpc7.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]..cctor()
   Exception_EndOfInnerExceptionStack
   at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultClientFactory.CreateClient[IDictionaryService](CallInvoker channel)
   at Program.<>c.<<Main>$>b__0_1(IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite , RuntimeResolverContext )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite , RuntimeResolverContext )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite , RuntimeResolverContext , ServiceProviderEngineScope , RuntimeResolverLock )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite , RuntimeResolverContext )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite , ServiceProviderEngineScope )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass4_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier , ServiceProviderEngineScope )
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type )
   at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass9_0.<CreatePropertyInjector>g__Initialize|1(IServiceProvider serviceProvider, IComponent component)
   at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider , Type , IComponentRenderMode , Nullable`1 )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame[] , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer , RenderBatchBuilder , Int32 , ArrayRange`1 , ArrayRange`1 )
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder , RenderFragment , Exception& )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

.NET Version

8.0.304

Anything else?

Visual Studio 2022 version

17.10.6

Docker version

> docker --version
Docker version 27.2.0, build 3ab4256

Dotnet Info

> dotnet --info
.NET SDK:
 Version:           8.0.304
 Commit:            352dc5a01f
 Workload version:  8.0.300-manifests.113cb230
 MSBuild version:   17.10.4+10fbfbf2e

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.304\

.NET workloads installed:
 [wasm-tools]
   Installation Source: VS 17.10.35201.131
   Manifest Version:    8.0.8/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.current\8.0.8\WorkloadManifest.json
   Install Type:        FileBased


Host:
  Version:      8.0.8
  Architecture: x64
  Commit:       08338fcaa5

.NET SDKs installed:
  2.2.109 [C:\Program Files\dotnet\sdk]
  5.0.416 [C:\Program Files\dotnet\sdk]
  7.0.410 [C:\Program Files\dotnet\sdk]
  8.0.304 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Sep 24, 2024
@halter73 halter73 added the area-grpc Includes: GRPC wire-up, templates label Sep 24, 2024
@halter73
Copy link
Member

@JamesNK Do you know what's going on here with System.TypeInitializationException: TypeInitialization_Type, DefaultProxyCache1`. It looks like they're using gRPC (web?) from Blazor WASM?

@halter73
Copy link
Member

halter73 commented Sep 24, 2024

fail: Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery[7]
An exception was thrown while deserializing the token.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.

This indicates that data protection is likely not configured correctly. That said, if you are not using antiforgery tokens for any form posts and you aren't using data protection for anything else like cookies, this failure log should be benign.

https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?view=aspnetcore-8.0

@JamesNK
Copy link
Member

JamesNK commented Sep 24, 2024

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: TypeInitialization_Type, DefaultProxyCache1 System.TypeInitializationException: TypeInitialization_Type, DefaultProxyCache1
---> System.Reflection.TargetInvocationException: Arg_TargetInvocationException
---> System.InvalidOperationException: No marshaller available for System.Collections.Generic.Dictionary2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] at ProtoBuf.Grpc.Internal.MarshallerCache.<GetMarshaller>g__Throw|5_0[Dictionary2]()

This error is coming from https://github.com/protobuf-net/protobuf-net.Grpc. This gRPC library is community created and we don't know how it works and can't support it. Please create an issue on their repo about this error.

@japtar10101
Copy link
Author

Filed an issue to protobuf-net.Grpc:
protobuf-net/protobuf-net.Grpc#336

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components area-grpc Includes: GRPC wire-up, templates
Projects
None yet
Development

No branches or pull requests

3 participants