Forum d'entraide Acomba
Pourquoi ne pas devenir membre du forum ?

Identifiez-vous ou Inscrivez-vous afin d'accéder à l'inrégralité du forum:
Accès à toutes les catégories du forum,
Entraide entre les 6 500 membres, et ce nombre s'accroît quotidiennement!

Notez que ce forum est indépendant de la société Acceo Solutions, éditrice du logiciel Acomba.

Rejoignez le forum, c’est rapide et facile

Forum d'entraide Acomba
Pourquoi ne pas devenir membre du forum ?

Identifiez-vous ou Inscrivez-vous afin d'accéder à l'inrégralité du forum:
Accès à toutes les catégories du forum,
Entraide entre les 6 500 membres, et ce nombre s'accroît quotidiennement!

Notez que ce forum est indépendant de la société Acceo Solutions, éditrice du logiciel Acomba.
Forum d'entraide Acomba
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
Connexion
-40%
Le deal à ne pas rater :
-40% sur le Pack Gaming Mario PDP Manette filaire + Casque filaire ...
29.99 € 49.99 €
Voir le deal

Aller en bas
avatar
will
Nombre de messages : 9
Date d'inscription : 29/09/2021

Fiche d'Entreprise
Nom de l'entreprise:

Acomba SDK en conjonction avec DI, objet non enregistré ? Empty Acomba SDK en conjonction avec DI, objet non enregistré ?

Mar 12 Oct 2021 - 9:31
Je développe un service windows qui fait le pont avec acomba.  Le service surveille un dossier pour des fichiers transactionnels puis les traite lorsqu'il en trouve.

Comme tout service windows, le point d'entrée est la classe Program, en C#.  C'est donc là que j'initialise, en terme DI, mes services.  Afin de sépararer les responsabilités, je me suis créé une classe que j'ai nommé NinjectCompositionRoot.  Au sein de celle-ci j'utilise simplement l'outil Ninject et les liaisons de type par convention (convention binding).

Voici un exemple :
Code:

public class NinjectCompositionRoot {
    private readonly IKernel _services;
    private NinjectCompositionRoot()
        => _services = new StandardKernel(new AutoMapperModule(), new AcombaBindingModule());

    public IKernel RegisterServices() {
        _services.Bind(services => services
            .FromThisAssembly()
            .SelectAllClasses()
            .BindAllInterfaces());

        return _services;
    }
}

Comme le sdk acomba est constitué d'objects com, les classes ne peuvent être instancié directement, car celles-ci ne peuvent être intégrées à l'assembly qui fait référence au sdk.  Par ailleurs, des interfaces d'interpolation sont créées pour pouvoir instancier les objets et les utiliser.

Code:

[ComImport]
[TypeLibType(TypeLibTypeFlags.FDual | TypeLibTypeFlags.FDispatchable)]
[Guid("00000114-0000-000F-1000-000AC0BA1001")]
public interface IAcoSDKX { ... }

[ComImport]
[Guid("00000114-0000-000F-1000-000AC0BA1001")]
[CoClass(typeof(AcoSDKXClass))]
public interface AcoSDKX { ... }

Ce qui permet alors de faire :

Code:

IAcoSDKX sdk = new AcoSDKX();  // Et ce même si les deux types ici présents sont des interfaces.

Mais comme j'utilise l'injection de dépendances, j'essaie donc d'instruire Ninject sur comment instancier ces objets par convention comme suit :

Code:

public class AcombaBindingModule : NinjectModule {
    public override void Load()
        => AppDomain.CurrentDomain
                     .GetAssemblies()
                     .Single(a => a.GetTypes().Contains(typeof(AcoSDKX)))
                     .GetExportedTypes()
                     .Where(t => t.IsInterface && !t.Name.StartsWith("I"))
                     .ToList()
                     .ForEach(type => {
                         var bindingType = type.GetInterfaces().Single(i => i.Name.Contains(type.Name));
                         var typeFromCLSID = Type.GetTypeFromCLSID(type.GUID);
                         Kernel.Bind(bindingType).ToMethod(_ => Activator.CreateInstance(typeFromCLSID));
                     });
}

En exécution, j'obtiens l'exception :


System.Runtime.InteropServices.COMException: 'Retrieving the COM class factory for component with CLSID {00000114-0000-000F-1000-000AC0BA1001} failed due to the following error:  80040154  Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).'

J'ai pourtant enregistré la dll acosdk.dll à l'aide de regsvr32, et si j'instancie en faisant un new, ça fonctionne.

Code:

public class AcombaBindingModule : NinjectModule {
    public override Load() {
        Kernel.Bind<IAcoSDKX>().ToMethod(_ => new AcoSDKX());
        Kernel.Bind<IAcombaX>().ToMethod(_ => new AcombaX());
        Kernel.Bind<IUser>().ToMethod(_ => new User());
    }
}

Je reconnais que c'est pas directement en lien avec le sdk d'acomba et plutôt avec les objets COM en général.  Et si qqn pouvait m'aider, je l'apprécierais vraiment !  Mon but serait que Ninject puisse instancier toutes les dépendances aux objets COM au fur et à mesure que je les utilise de sorte que je n'aie plus à rejouer avec le composition root.


Dernière édition par will le Mar 12 Oct 2021 - 9:38, édité 3 fois (Raison : Reformatté le code d'AcombaBindingModule par convention pour améliorer l'affichage et le lecture.)
avatar
will
Nombre de messages : 9
Date d'inscription : 29/09/2021

Fiche d'Entreprise
Nom de l'entreprise:

Acomba SDK en conjonction avec DI, objet non enregistré ? Empty Re: Acomba SDK en conjonction avec DI, objet non enregistré ?

Mar 19 Oct 2021 - 13:28
J'ai abdiqué et j'ai décidé de créer un module Acomba où je "bind" tous les types utilisés.  Cela nécessite que j'oublie pas de bien ajouter les types qui seraient nouvellement utilisés, autrement une exception sera levée lors de l'exécution.

Code:

            public class AcombaModule : NinjectModule {
                public override void Load() {
                    Kernel.Bind<IAcoSDKX>().ToMethod(_ => new AcoSDKX()).InSingletonScope();
                    Kernel.Bind<IAcombaX>().ToMethod(_ => new AcombaX()).InSingletonScope();
                    Kernel.Bind<IUser>().ToMethod(_ => new User()).InSingletonScope();
                    Kernel.Bind<ISupplier>().ToMethod(_ => new Supplier());
                    Kernel.Bind<ICharter>().ToMethod(_ => new Charter());
                    Kernel.Bind<IPayables>().ToMethod(_ => new Payables());
                    Kernel.Bind<ITransAP>().ToMethod(_ => new TransAP());
                    Kernel.Bind<IPaymentAP>().ToMethod(_ => new PaymentAP());
                    Kernel.Bind<IInvoiceAP>().ToMethod(_ => new InvoiceAP());
                    Kernel.Bind<IPaymentAPLine>().ToMethod(_ => new PaymentAPLine());
                }
            }

Simplement ne pas oublier d'ajouter le module au noyau de Ninject.  Pour ce faire, j'ai décidé d'y aller avec une extension.

Code:

namespace Ninject {
    public static class KernelExtensions {
        public static IKernel BindAcomba(this IKernel kernel) {
            kernel.Load<NinjectCompositionRoot.Modules.AcombaModule>();
            return kernel;
        }
    }
}

Et j'appelle donc cette méthode lors de l'enregistrement des services.

Code:

        public IKernel RegisterServices() {
            _services.BindMediatR();
            _services.BindAutoMapper();
            _services.BindAcomba();

            _services.Bind(services => services.FromThisAssembly().SelectAllClasses().BindAllInterfaces());

            return _services;
        }
Revenir en haut
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum