Closed isatahiri closed 3 years ago
UnableToOpenDatabaseException
This tell us that everything up to there, assembly loading etc. went well, but there is a connectivity problem. Without the module starts?
I agree. But if i remove :
RequiredModuleTypes.Add(typeof(Xpand.XAF.Modules.SequenceGenerator.SequenceGeneratorModule));
from the module.cs, then I can connect to the app.
So that means that the sequence generator uses the CS before the logging on ? Or it uses the CS in the configuration file and not the ObjectSpace ?
I do not see any change in this Expand module since 30.01.2021 according to Github history... So i'm a bit lost. How can this work in 20.2.7 and not in 21.1.3... Must be a DX breaking change that I missed.
at DevExpress.Xpo.DB.MySqlConnectionProvider.CreateDataBase()
hmmm, hard to tell. The module uses the Xpand.XAF.Modules.SequenceGenerator.Extensions.GetConnectionString method can u see its value OnBeForeLogin?
I do not see any change in this Expand module
yeah but there are dependecies so u really not know unless u have tests which again are only indicators
Well I have not tested but I do not expect to see the CS on OnBeForeLogin as I set the CS on OnLoggingOn. The method that you mentioned gets the CS of an objectSpaceProvider so it this is done after the login, there no reason to fail.
Maybe something is wrong with my method here ?
protected override void OnLoggingOn(LogonEventArgs args) { base.OnLoggingOn(args); try { IConfiguration configuration = ServiceProvider.GetRequiredService<IConfiguration>(); var adminCS = configuration.GetConnectionString("AdminConnectionString"); var brokerAdminDal = XpoDefault.GetDataLayer(adminCS, DevExpress.Xpo.DB.AutoCreateOption.None); using (var baUow = new UnitOfWork(brokerAdminDal)) { var username = ((AuthenticationStandardLogonParameters)args.LogonParameters).UserName; BrokeroAdmin.Module.BO.TenantAccess tenantAccess = baUow.Query<BrokeroAdmin.Module.BO.TenantAccess>() .Where(ta => ta.Access.UserAccess == username) .First(); if (tenantAccess != null) { ((XPObjectSpaceProvider)ObjectSpaceProviders[0]).SetDataStoreProvider(GetDataStoreProvider(tenantAccess.Tenant.ConnectionString, null)); } } } catch { throw new UserFriendlyException($"Nom d'utilsateur ou mot de passe inconnu. Veuillez vérifier les données entrées ou appeler le support technique."); } }
Then this become a real blocking point for me.
Any suggestion would be very welcome! Do u need a sample project?
internal static IObservable<Unit> Connect(this ApplicationModulesManager manager,Type sequenceStorageType=null){
sequenceStorageType ??= typeof(SequenceStorage);
Guard.TypeArgumentIs(typeof(ISequenceStorage),sequenceStorageType,nameof(sequenceStorageType));
return manager.WhenApplication(application => application.WhenCompatibilityChecked().FirstAsync().Select(xafApplication => xafApplication.ObjectSpaceProvider)
.Where(provider => !provider.IsInstanceOf("DevExpress.ExpressApp.Security.ClientServer.MiddleTierServerObjectSpaceProvider"))
.SelectMany(provider => provider.SequenceGeneratorDatalayer()
.SelectMany(dataLayer => application.WhenObjectSpaceCreated().GenerateSequences(dataLayer,sequenceStorageType)
.Merge(application.Security.AddAnonymousType(sequenceStorageType).ToObservable()))
.Merge(application.ConfigureDetailViewSequenceStorage()).ToUnit()));
}
according to the source code SequenceGenerator.Connect
method the SequenceGenerator Layer is contructed after the First WhenCompatibilityChecked. For some reason this method is called (it shouldn't) before the correct CS is assigned
I created a sample project where i give the cs on the OnLoggingOn. I hope this will help. TestNet5.zip
hmm there is some confusion here, y9ou need to find out which connectionstring is used from Sequencegenetator. The modules as I mentioed subsrbes to the sequence generated after the first ObjectSpace is created actually after the CompatibilityChecked. This by design happens after login, in your solution something is diffenrent so i suggested to override the Login and check the value of s.
var s = ((XPObjectSpaceProvider) ObjectSpaceProviders[0]).GetConnectionString();
hope i make more sense now
After some research this seems to be coming from here :
The pooling was not activated. I'm not sure of what it means but after enabling this it works in the sample. Now this does not work in my solution... The app starts but when i create a record, it does not increment the sequencial number. I need to find why.
remember the module uses an ExplicitUnitOfWork maybe your Updaters ??
In the there is nothing related to the SequenceGenerator module in both solution. Here is the diffs in ObjectSpaceProviders between the sample and my app. Nothing wrong here.. Both type are supported i guess.
maybe calling this XpoDefault.GetDataLayer(objectSpaceProvider.GetConnectionString()) at the appropriate place depending on what logic u have in your create first object space area (by default after login)
maybe calling this XpoDefault.GetDataLayer(objectSpaceProvider.GetConnectionString())
calling it in order to try to understand the problem not as a fix, it should throw there in place where u can examine the objectSpaceProvider.GetConnectionString() and can see the problem.
having DX symbols in place I would set a breakpoint in XafApplication.CheckCombatibility and see who makes the first caLL that results in the exception
hmm. Not sure I understand this Tolis. I mean I understand but not sure i'm able to analyse that deep by myself.
So as info, the migration of my app to 21.1.3 was a nightmare because of migration to .net 5. So what I did last week was :
I seems that some code was missing/forgotten which I added right now :
With this, it seems to work now.
Note that with this the app is much slower as it is goes in getter and setter many many time.
This peace of code is I guess from the first implementation of the Sequence Generator. It does not look very clean does it ?
i do not recognize this code try to repro it a sample by adding parts as u did b4, start first from the SequenceGen module which works in a sample app then add incrementally your components as u did before until you find what to blame. You know the drill, it always works
So i did create a new sample using the SecuredObjectSpaceProvider instead of XPObjectSpaceProvider and i confirm that without adding this in the BlazorApplication.cs it does not work :
private static ConcurrentDictionary<string, bool> isCompatibilityChecked = new ConcurrentDictionary<string, bool>(); protected override bool IsCompatibilityChecked { get => isCompatibilityChecked.GetOrAdd(ConnectionString, false); set => isCompatibilityChecked.TryAdd(ConnectionString, value); }
Can this be related the the problematic that Dennis is exposed some years ago ?
where did u find the snippet? r u in middletier?
I'm not in middletier... When you create a Blazor app with standard authentification, then you ObjectSpaceProvider is DevExpress.ExpressApp.Security.ClientServer.SecuredSessionObjectLayer. If you create a Blazor app without authentification, then your ObjectSpaceProvider is XPObjectSpaceProvider.
In the new sample, if you are running with DevExpress.ExpressApp.Security.ClientServer.SecuredSessionObjectLayer the app runs but does not increment.
In the method WhenSupported which seems the be used by the Generate sequence, do this check :
if (space.UnitOfWork().DataLayer is BaseDataLayer dataLayer)
not sure what it means ? is this related somehow ?
the last sample works fine in my side, had to comment out the
string connectionsString = @"Integrated Security=SSPI;Pooling=false;Data Source=(localdb)\mssqllocaldb;Initial Catalog=DXApplication3";
((XPObjectSpaceProvider)ObjectSpaceProviders[0]).SetDataStoreProvider(GetDataStoreProvider(connectionsString, null));
cause I do not see why it is used
Sorry Tolis i had a typo issue in my example.
Please past the OnLoggingOn by this :
protected override void OnLoggingOn(LogonEventArgs args) { base.OnLoggingOn(args); try { string connectionsString = @"Integrated Security=SSPI;Pooling=false;Data Source=(localdb)\mssqllocaldb;Initial Catalog=DXApplication3"; ((XPObjectSpaceProvider)ObjectSpaceProviders[0]).SetDataStoreProvider(GetDataStoreProvider(connectionsString, null)); } catch { throw new UserFriendlyException($"Nom d'utilsateur ou mot de passe inconnu. Veuillez vérifier les données entrées ou appeler le support technique."); } }
And if you comment this part :
private static ConcurrentDictionary<string, bool> isCompatibilityChecked = new ConcurrentDictionary<string, bool>(); protected override bool IsCompatibilityChecked { get => isCompatibilityChecked.GetOrAdd(ConnectionString, false); set => isCompatibilityChecked.TryAdd(ConnectionString, value); }
After this you will see that the increment does not work.
cause I do not see why it is used
The point of this to set the CS in the OnLoggingOn after the user enters his credentials.
I am asking u again, where did u find this line?
private static ConcurrentDictionary<string, bool> isCompatibilityChecked = new ConcurrentDictionary<string, bool>(); protected override bool IsCompatibilityChecked { get => isCompatibilityChecked.GetOrAdd(ConnectionString, false); set => isCompatibilityChecked.TryAdd(ConnectionString, value); }
With the new prelease 4.211.0.5, I cannot start the app if I add the sequence generator in the required module : RequiredModuleTypes.Add(typeof(Xpand.XAF.Modules.SequenceGenerator.SequenceGeneratorModule));
Note that i'm using the connection string is given on the fly on the OnLoggingOn. This was working in the 20.2.7. What has changed ?
` he error occurred:
---> System.AggregateException: One or more errors occurred. (Hôte inconnu.) ---> System.Net.Sockets.SocketException (11001): Hôte inconnu. at System.Net.NameResolutionPal.ProcessResult(SocketError errorCode, GetAddrInfoExContext context) at System.Net.NameResolutionPal.GetAddressInfoExCallback(Int32 error, Int32 bytes, NativeOverlapped overlapped) --- End of stack trace from previous location ---
--- End of inner exception stack trace --- at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at MySql.Data.Common.StreamCreator.GetTcpStream(MySqlConnectionStringBuilder settings, MyNetworkStream& networkStream) at MySql.Data.Common.StreamCreator.GetStream(MySqlConnectionStringBuilder settings, MyNetworkStream& networkStream) at MySql.Data.MySqlClient.NativeDriver.Open() at MySql.Data.MySqlClient.NativeDriver.Open() at MySql.Data.MySqlClient.Driver.Open() at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings) at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection() at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection() at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver() at MySql.Data.MySqlClient.MySqlPool.GetConnection() at MySql.Data.MySqlClient.MySqlConnection.Open() at DevExpress.Xpo.DB.MySqlConnectionProvider.CreateDataBase()' Data: 0 entries Stack trace:
at DevExpress.Xpo.DB.MySqlConnectionProvider.CreateDataBase() at DevExpress.Xpo.DB.ConnectionProviderSql..ctor(IDbConnection connection, AutoCreateOption autoCreateOption) at DevExpress.Xpo.DB.MySqlConnectionProvider..ctor(IDbConnection connection, AutoCreateOption autoCreateOption) at DevExpress.Xpo.DB.MySqlConnectionProvider.CreateProviderFromConnection(IDbConnection connection, AutoCreateOption autoCreateOption) at DevExpress.Xpo.DB.MySqlConnectionProvider.CreateProviderFromString(String connectionString, AutoCreateOption autoCreateOption, IDisposable[]& objectsToDisposeOnDisconnect) at DevExpress.Xpo.DB.DataStoreBase.QueryDataStore(String providerType, String connectionString, AutoCreateOption defaultAutoCreateOption, IDisposable[]& objectsToDisposeOnDisconnect) at DevExpress.Xpo.XpoDefault.GetConnectionProvider(String connectionString, AutoCreateOption defaultAutoCreateOption, IDisposable[]& objectsToDisposeOnDisconnect) at DevExpress.Xpo.XpoDefault.GetDataLayer(String connectionString, XPDictionary dictionary, AutoCreateOption defaultAutoCreateOption, IDisposable[]& objectsToDisposeOnDisconnect) at DevExpress.Xpo.XpoDefault.GetDataLayer(String connectionString, XPDictionary dictionary, AutoCreateOption defaultAutoCreateOption) at Xpand.XAF.Modules.SequenceGenerator.SequenceGeneratorService.<>c__DisplayClass37_0.b_0()
at System.Reactive.Linq.ObservableImpl.Defer`1..Run() in /_/Rx.NET/Source/src/System.Reactive/Linq/Observable/Defer.cs:line 37
at MySql.Data.MySqlClient.NativeDriver.Open() at MySql.Data.MySqlClient.Driver.Open() at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings) at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection() at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection() at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver() at MySql.Data.MySqlClient.MySqlPool.GetConnection() at MySql.Data.MySqlClient.MySqlConnection.Open() at DevExpress.Xpo.DB.MySqlConnectionProvider.CreateDataBase()
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at MySql.Data.Common.StreamCreator.GetTcpStream(MySqlConnectionStringBuilder settings, MyNetworkStream& networkStream) at MySql.Data.Common.StreamCreator.GetStream(MySqlConnectionStringBuilder settings, MyNetworkStream& networkStream) at MySql.Data.MySqlClient.NativeDriver.Open()
at System.Net.NameResolutionPal.ProcessResult(SocketError errorCode, GetAddrInfoExContext context) at System.Net.NameResolutionPal.GetAddressInfoExCallback(Int32 error, Int32 bytes, NativeOverlapped overlapped) --- End of stack trace from previous location ---
`