microsoft / PowerPlatform-DataverseServiceClient

Code Replica for Microsoft.PowerPlatform.Dataverse.Client and supporting nuget packages.
MIT License
271 stars 49 forks source link

Is use of the client in Blazor WASM supported? #441

Open iddycol opened 3 months ago

iddycol commented 3 months ago

When attempting to use the Dataverse client in a Blazor WASM application (Vs2022 / .NET 8.0) I have a "not supported on this platform" exception. Is this a bug, a configuration I need too apply or just not possible on this platform?

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Failed to connect to Dataverse Microsoft.PowerPlatform.Dataverse.Client.Utils.DataverseConnectionException: Failed to connect to Dataverse ---> System.PlatformNotSupportedException: Operation is not supported on this platform. at System.Net.Http.BrowserHttpHandler.set_UseCookies(Boolean value) at System.Net.Http.HttpClientHandler.set_UseCookies(Boolean value) at Microsoft.PowerPlatform.Dataverse.Client.Utils.ClientServiceProviders.<>c.b3_0() at Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.<>c__DisplayClass5_0.b1(HttpMessageHandlerBuilder b) at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>cDisplayClass17_0.gConfigure|0(HttpMessageHandlerBuilder b) at Microsoft.Extensions.Http.LoggingHttpMessageHandlerBuilderFilter.<>cDisplayClass2_0.b0(HttpMessageHandlerBuilder builder) at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandlerEntry(String name) at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>c__DisplayClass14_0.<.ctor>b__1() at System.Lazy1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ViaFactory(LazyThreadSafetyMode mode) at System.Lazy1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].CreateValue() at System.Lazy1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].get_Value() at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler(String name) at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(String name) at Microsoft.PowerPlatform.Dataverse.Client.Auth.AuthProcessor.GetAuthorityFromTargetServiceAsync(IHttpClientFactory clientFactory, Uri targetServiceUrl, DataverseTraceLogger logger, Boolean isOnPrem) at Microsoft.PowerPlatform.Dataverse.Client.Auth.AuthProcessor.ExecuteAuthenticateServiceProcessAsync(Uri serviceUrl, ClientCredentials clientCredentials, X509Certificate2 userCert, String clientId, Uri redirectUri, PromptBehavior promptBehavior, Boolean isOnPrem, String authority, Object msalAuthClient, DataverseTraceLogger logSink, Boolean useDefaultCreds, SecureString clientSecret, Boolean addVersionInfoToUri, IAccount user, MemoryBackedTokenCache memoryBackedTokenCache, String tokenCacheStorePath) at Microsoft.PowerPlatform.Dataverse.Client.ConnectionService.ConnectAndInitServiceAsync(OrganizationDetail orgdata, Boolean IsOnPrem, Uri homeRealmUri) at Microsoft.PowerPlatform.Dataverse.Client.ConnectionService.DoDirectLoginAsync(Boolean IsOnPrem) at Microsoft.PowerPlatform.Dataverse.Client.ConnectionService.InitServiceAsync() at Microsoft.PowerPlatform.Dataverse.Client.ConnectionService.GetCachedService(ConnectionService& ConnectionObject) at Microsoft.PowerPlatform.Dataverse.Client.ConnectionService.IntilizeService(ConnectionService& ConnectionObject) at Microsoft.PowerPlatform.Dataverse.Client.ConnectionService.DoLogin(ConnectionService& ConnectionObject) at Microsoft.PowerPlatform.Dataverse.Client.ServiceClient.CreateServiceConnection(Object externalOrgServiceProxy, AuthenticationType requestedAuthType, String hostName, String port, String orgName, NetworkCredential credential, String userId, SecureString password, String domain, String Geo, String claimsHomeRealm, Boolean useSsl, Boolean useUniqueInstance, OrganizationDetail orgDetail, String clientId, Uri redirectUri, PromptBehavior promptBehavior, OrganizationWebProxyClientAsync externalOrgWebProxyClient, String certificateThumbPrint, StoreName certificateStoreName, X509Certificate2 certificate, Uri instanceUrl, Boolean isCloned, Boolean useDefaultCreds, Version incomingOrgVersion, ILogger externalLogger, String tokenCacheStorePath) --- End of inner exception stack trace --- at Microsoft.PowerPlatform.Dataverse.Client.ServiceClient.CreateServiceConnection(Object externalOrgServiceProxy, AuthenticationType requestedAuthType, String hostName, String port, String orgName, NetworkCredential credential, String userId, SecureString password, String domain, String Geo, String claimsHomeRealm, Boolean useSsl, Boolean useUniqueInstance, OrganizationDetail orgDetail, String clientId, Uri redirectUri, PromptBehavior promptBehavior, OrganizationWebProxyClientAsync externalOrgWebProxyClient, String certificateThumbPrint, StoreName certificateStoreName, X509Certificate2 certificate, Uri instanceUrl, Boolean isCloned, Boolean useDefaultCreds, Version incomingOrgVersion, ILogger externalLogger, String tokenCacheStorePath) at Microsoft.PowerPlatform.Dataverse.Client.ServiceClient.ConnectToService(String connectionString, ILogger logger) at Microsoft.PowerPlatform.Dataverse.Client.ServiceClient..ctor(String dataverseConnectionString, ILogger logger) at Strategik_365_Blazor.STK365Blazor.GetDataverseHelper() at StrategikUI.Pages.STK365SystemDesigner.OnInitialized() in C:\Dev\blazordesigner\app\Pages\STK365SystemDesigner.razor:line 50 at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

MattB-msft commented 3 months ago

Web Assembly in general, has several specific rules about what does and does not work. We have not fully tested DVSC with Web Assembly, we have tested it with Blazor Apps on server.

In this case, looking at the error, it looks like you're trying to use the DVSC onboard auth, which is using MSAL, which is what is throwing the error when it's trying to manage the HTTP connection.

My first guidance here would be to use a custom auth hander to avoid the MSAL lib dependencies on auth flow. though the real answer may be that we need to ship the .net standard targets for DVSC for this to work properly for you .

if you have a test project you're willing to share we can take a look.

iddycol commented 3 months ago

Thanks Matt - I think may way forward will be to switch to a server hosted app for now as that's going to be required for some of the other functionality I need to create.

iddycol commented 3 months ago

Hi Matt - I've created a simple blazor server side component to test the client using the client id and secret registered in my tenant. It throws a null reference exception from the service client constructor. Did you test with .NET 8.0 / latest version of Blazor on the server? Can you share a working example (or I can share this project with you if you need it).

MattB-msft commented 3 months ago

We test Blazor using a custom AAD auth provider, the scenario we use there is Onbehalf of auth, We have not tested with the onboard S2S auth.
will chat with the team about it and see if we can set it up to take a look.

Generally though, you should look at the auth provider in this example here: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/quick-start-blazor-server-app You would wire that into the "get token" call for the DVSC.