IoC, Unity e parametri di passaggio (o un modo per evitare di farlo)

2

Anche se il concetto di IoC non mi è estraneo, sono nuovo di Unity e ho difficoltà a connettere i punti metaforici, per così dire.

Nel nostro progetto abbiamo una libreria di classi per la logica, quindi diverse librerie di classi con repository che implementano interfacce comuni (forniscono accesso e consentono operazioni CRUD su diverse origini dati). Infine, tutto questo viene utilizzato insieme in un sito Web MVC o in un sito di SharePoint.

Volevamo implementare Unity per mantenere una singola configurazione e migliorare il tutto.

Ma ... ci sono alcuni problemi di progettazione che sto affrontando. Ad esempio, il sito Web MVC, per quanto riguarda la comunicazione con il database SQL sottostante, può disporre di tutto ciò che deve essere specificato nella sezione di configurazione per il contenitore Unity. Tuttavia, detto sito Web deve anche collegarsi occasionalmente con SharePoint ... per creare un repository SharePoint, ho bisogno di creare un oggetto SPWeb e passarlo al costruttore del repository.

POSSO farlo usando ParameterOverride quando risolvo il tipo, ma questo non ... mi sembra giusto. Ci sono casi in cui un numero maggiore di parametri deve essere sovrascritto in questo modo; per risolvere una classe logica ho bisogno di passare repository, che a loro volta vengono risolti passando un oggetto SPWeb creato manualmente ... Quando ciò accade sembra che non stia più seguendo un pattern IoC. Il kicker è che non posso avere l'oggetto SPWeb definito nel contenitore Unity!

Esiste un modello (un esempio pratico sarebbe superbo) dove viene usato Unity ma determinati valori vengono passati al contenitore durante la risoluzione dei tipi, senza la necessità di usare ParameterOverride ?

Modifica

Credo di dover fornire un esempio più specifico del perché ParameterOverride è un problema. Di seguito è riportato un frammento di codice utilizzato da un processo timer di SharePoint. Il lavoro in questione sincronizza alcuni dati tra SharePoint e SQL, quindi richiede due diversi repository che implementano la stessa interfaccia. Poiché il codice viene eseguito da SharePoint, non può accedere a una configurazione globale definita DataContext (EntityFramework, code-first) poiché non esiste un file web.config da cui leggere la stringa di connessione. Inoltre, a causa della stranezza che è SharePoint, non riesco a "ottenere" l'attuale oggetto SPWeb , e invece ho bisogno di crearlo al volo.

Il risultato finale è una tonnellata su using e molti parametri devono essere sovrascritti quando si usa Resolve . Inoltre, la necessità di passare il parametro NAME come una stringa renderebbe questo codice molto difficile per chiunque altro: questa informazione non è nota dall'interfaccia.

    public override void Execute(Guid targetInstanceId)
    {
        var siteUrl = Properties["Site"] as string;
        var sqlConnection = Properties["SQL"] as string;
        if (String.IsNullOrEmpty(siteUrl))
            throw new ArgumentNullException("Site URL is missing.");
        if (String.IsNullOrEmpty(sqlConnection))
            throw new ArgumentNullException("SQL connection string is missing.");

        using (var site = new SPSite(siteUrl, SPUserToken.SystemAccount))
        using (var web = site.OpenWeb())
        using (var spPollRepository = Configuration.ServiceLocator.SharePointContainer.Container.Resolve<IPollRepository>(new ParameterOverride("web", web)))
        using (var ctx = Configuration.ServiceLocator.SharePointContainer.Container.Resolve<Repositories.PollsDataContext>(Configuration.ServiceLocator.SqlNamedRegistration, new ParameterOverride("nameOrConnectionString", sqlConnection), new ParameterOverride("initialize", false)))
        using (var sqlPollRepository = Configuration.ServiceLocator.SharePointContainer.Container.Resolve<IPollRepository>(Configuration.ServiceLocator.SqlNamedRegistration, new ParameterOverride("ctx", ctx)))
        {
            IPollsSyncLogic logic = Configuration.ServiceLocator.SharePointContainer.Container.Resolve<Logic.IPollsSyncLogic>(new ParameterOverride("sqlRepository", sqlPollRepository), new ParameterOverride("spRepository", spPollRepository));
            logic.SyncPolls();
        }
    }

C'è una grande possibilità che sto usando Unity ... sbagliato. O che qualche altra definizione fondamentale è stata confusa. Spero che questo chiarisca ogni confusione sulla questione.

    
posta Shaamaan 19.11.2014 - 11:39
fonte

1 risposta

1

Se le entità restituite dal repository SharePoint sono specifiche, è sufficiente creare un'interfaccia [TheEntity]Repository con una singola implementazione che dialoga con SharePoint.

Se l'interfaccia [TheEntity]Repository ha due implementazioni che parlano rispettivamente di SharePoint e un database SQL, puoi utilizzare ResolvedParameters al momento della configurazione (non Overrides al tempo di risoluzione ) per iniettare il repository concreto giusto a seconda del tipo in cui viene iniettato.

Modifica

Vedendo il codice che hai postato, il grande difetto è che ti piacerebbe usare IOC e repository astratti, ma questo è rovinato dal fatto che IPollsSyncLogic conosce perfettamente Sql e Sharepoint, dal momento che il suo costruttore ha due parametri chiamati esplicitamente sqlRepository e spRepository.

Dovresti o

  • Adotta completamente la specificità di IPollsSyncLogic come sincronizzatore SP / SQL utilizzando i tipi di repository SQL e SP espliciti nella sua firma del costruttore.

o

  • Crea IPollsSyncLogic un sincronizzatore più astratto tra due implementazioni della stessa interfaccia del repository. In tal caso, basta denominare i parametri del costruttore qualcosa come repositorySource e repositoryTarget . Nella configurazione IoC, utilizzare InjectionFactory per specificare i due tipi di repository concreti.

Come nota a margine, dovresti evitare di ricorrere a Container.Resolve e basarti su una risoluzione automatica basata sulla configurazione quando possibile, perché le chiamate discrete al contenitore sono solitamente delle dipendenze nascoste. Per le dipendenze che fanno parte delle istruzioni using e non possono essere immesse tramite un costruttore, puoi fare affidamento su una Factory che le produce al volo.

Per quanto riguarda il tuo problema con l'accesso di SharePoint a DataContext , penso che meriti una domanda a parte.

    
risposta data 19.11.2014 - 17:28
fonte

Leggi altre domande sui tag