Open Closed

Dotnet Maui App Is it possible to Remove Autofac #6632


User avatar
0
cangunaydin created
  • ABP Framework version: v8.0
  • UI Type: Maui
  • Database System: EF Core
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes

Hello, I was trying to publish my maui app to appstore but it is rejected. The reason behind is app crashing on startup when it is on release. After I check it up, i understand that reason behind is autofac module. Since it uses reflections and ios doesn't allow it. If you are debugging your app in maui, useinterpreter property is on. So the app is not crashing. There is a discussion over here about the problem. https://github.com/dotnet/maui/issues/13019

But when you switch to release mode since it makes your app slow down, it is turned off and the problem arises. So at the end i decided to create all my httpclient projects as static and remove the autofac from maui app. I had a previous issue that i open a ticket. You can find it here. In that case it was avalonia app. https://support.abp.io/QA/Questions/6476/Problem-using-httpclient-module-in-avalonia-ios-or-xamarin-forms-ios-projects

I managed to fix the issue on almost all appservices. Only problem right now is with authorizationservice. In this line i am getting "no policy found" error.

probably in the background since i removed autofac module authorization service is trying to do the same thing on the web server. It is not intercepted anymore i guess. Is there any way to fix that problem? Also i think maui project shouldn't depend on autofac since intercepting is no no for ios.


4 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    ABP uses the OnRegistered event to configure all permission Definitions. but it is a feature of autofac

    You need to configure them manually without autofac

  • User Avatar
    0
    cangunaydin created

    Thanks for the information. I have managed to fix it now. It works without autofac. here is the step by step what i did if somebody wants to do it.

    1- Change all your dynamic client proxies to static ones. 2- Remove Autofac from the project solution

    [DependsOn(
        typeof(AbpMauiClientModule),
        typeof(AbpHttpClientIdentityModelModule),
        typeof(DoohlinkHttpApiStaticClientModule), //your static client over here
        typeof(AbpAutoMapperModule)
    )]
    public class DoohlinkMauiModule : AbpModule
    {
    

    3- Remove Autofac from MauiProgram.cs it should be sth similar like this, I have created static methods to get the required service from dependency injection for the following steps.

     public static IAbpApplicationWithExternalServiceProvider? AbpApplication { get; private set; }
    
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()
                .ConfigureSyncfusionCore()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                    fonts.AddFont("Roboto-Regular.ttf", "Roboto");
                    fonts.AddMaterialIconFonts();
                });
    
            builder.ConfigureMauiHandlers(handlers =>
            {
                handlers.AddHandler(typeof(Entry), typeof(EntryVisualEffectsRemoverHandler));
                handlers.AddHandler(typeof(Picker), typeof(PickerVisualEffectsRemoverHandler));
                handlers.AddHandler(typeof(DatePicker), typeof(DatePickerVisualEffectsRemoverHandler));
            });
            ConfigureConfiguration(builder);
    
            builder.Services.AddApplication<DoohlinkMauiModule>(options =>
            {
                options.Services.ReplaceConfiguration(builder.Configuration);
            });
    
    #if DEBUG
            builder.Logging.AddDebug();
    #endif
            var app = builder.Build();
    
            AbpApplication = app.Services.GetRequiredService<IAbpApplicationWithExternalServiceProvider>();
            AbpApplication.Initialize(app.Services);
    
            return app;
        }
    
        public static T? GetRequiredService<T>() where T : class
        {
            return AbpApplication?.Services.GetRequiredService<T>();
        }
    
        public static object? GetRequiredService(Type type)
        {
            return AbpApplication?.Services.GetRequiredService(type);
        }
    

    4- ReplaceService for MauiCachedApplicationConfigurationClient. Add custom class

        [Volo.Abp.DependencyInjection.Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(ICachedApplicationConfigurationClient), typeof(MauiCachedApplicationConfigurationClient))]
    public class DoohlinkMauiCachedApplicationConfigurationClient : MauiCachedApplicationConfigurationClient
    {
        public DoohlinkMauiCachedApplicationConfigurationClient(
            AbpApplicationConfigurationClientProxy applicationConfigurationClientProxy,
            AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy,
            ApplicationConfigurationCache cache,
            ICurrentTenantAccessor currentTenantAccessor) : base(applicationConfigurationClientProxy,
            applicationLocalizationClientProxy, cache, currentTenantAccessor)
        {
            ApplicationConfigurationClientProxy.LazyServiceProvider =
                MauiProgram.GetRequiredService<IAbpLazyServiceProvider>()!;
            ApplicationLocalizationClientProxy.LazyServiceProvider = MauiProgram.GetRequiredService<IAbpLazyServiceProvider>()!;
        }
    }
    

    5- Change ViewModelBase, so it doesn't need LazyServiceProvider anymore.

       public abstract partial class DoohlinkViewModelBase : ObservableObject
    {
    
        public ICurrentTenant CurrentTenant { get; }
        
        public ICurrentUser CurrentUser { get; }
    
        public IAbpAuthorizationService AuthorizationService { get; }
    
        public LocalizationResourceManager L { get; }
    
        protected DoohlinkViewModelBase()
        {
            CurrentTenant = MauiProgram.GetRequiredService<ICurrentTenant>()!;
            CurrentUser = MauiProgram.GetRequiredService<ICurrentUser>()!;
            AuthorizationService = MauiProgram.GetRequiredService<IAbpAuthorizationService>()!;
            L = MauiProgram.GetRequiredService<LocalizationResourceManager>()!;
            
        }
    
        protected void HandleException(Exception exception, [CallerMemberName] string? methodName = null)
        {
            if (Application.Current is { MainPage: { } })
            {
                Application.Current.MainPage.DisplayAlert(L["Error"].Value, exception.Message, L["OK"].Value);
            }
        }
    }
    

    6- Change the MauiModule so lazyserviceprovider can be resolved when you call your app services.

     private void ConfigureServiceProviders(ServiceConfigurationContext context)
        {
            context.Services.Replace(ServiceDescriptor.Transient<IProfileAppService>(serviceProvider =>
            {
                var profileClientProxy = serviceProvider.GetRequiredService<ProfileClientProxy>();
                profileClientProxy.LazyServiceProvider = serviceProvider.GetRequiredService<IAbpLazyServiceProvider>();
                return profileClientProxy;
            }));
    
            context.Services.Replace(ServiceDescriptor.Transient<IIdentityUserAppService>(serviceProvider =>
            {
                var identityUserClientProxy = serviceProvider.GetRequiredService<IdentityUserClientProxy>();
                identityUserClientProxy.LazyServiceProvider = serviceProvider.GetRequiredService<IAbpLazyServiceProvider>();
                return identityUserClientProxy;
            }));
            context.Services.Replace(ServiceDescriptor.Transient<IAccountAppService>(serviceProvider =>
            {
                var accountClientProxy = serviceProvider.GetRequiredService<AccountClientProxy>();
                accountClientProxy.LazyServiceProvider = serviceProvider.GetRequiredService<IAbpLazyServiceProvider>();
                return accountClientProxy;
            }));
    
            context.Services.Replace(ServiceDescriptor.Transient<IScreenAppService>(serviceProvider =>
            {
                var screenClientProxy = serviceProvider.GetRequiredService<ScreenClientProxy>();
                screenClientProxy.LazyServiceProvider = serviceProvider.GetRequiredService<IAbpLazyServiceProvider>();
                return screenClientProxy;
            }));
    
    
            context.Services.Replace(ServiceDescriptor.Transient<ITenantAppService>(serviceProvider =>
            {
                var tenantClientProxy = serviceProvider.GetRequiredService<TenantClientProxy>();
                tenantClientProxy.LazyServiceProvider = serviceProvider.GetRequiredService<IAbpLazyServiceProvider>();
                return tenantClientProxy;
            }));
        }
    

    you need to add whatever appservice you use over here. Maybe this can be automated for the future.

    7- Add permissions manually.

        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            AddPermissions(context);
    #if DEBUG
            PreConfigure<AbpHttpClientBuilderOptions>(options =>
            {
                options.ProxyClientBuildActions.Add((_, clientBuilder) =>
                {
                    clientBuilder.ConfigurePrimaryHttpMessageHandler(GetInsecureHandler);
                });
            });
    #endif
        }
        private void AddPermissions(ServiceConfigurationContext context)
        {
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            var permissionDefinitionTypes = assemblies.SelectMany(o => o.GetTypes()).Where(o =>
                    typeof(IPermissionDefinitionProvider).IsAssignableFrom(o) &&
                    o.Name != nameof(IPermissionDefinitionProvider) && o.Name != nameof(PermissionDefinitionProvider))
                .Distinct().ToList();
    
            context.Services.Configure<AbpPermissionOptions>(options =>
            {
                options.DefinitionProviders.AddIfNotContains(permissionDefinitionTypes);
            });
        }
    

    And voila... I am gonna close this issue liangshiwei but one last question. How can I get the source code of AbpMauiClientModule? thank you for the help.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    It's open source: https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Maui.Client/Volo/Abp/Maui/Client/AbpMauiClientModule.cs

  • User Avatar
    0
    cangunaydin created

    oh nice, thank you. I think there are also many problems with the profile page but I can create a new ticket for them. thanks for your help.

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11