IoC (Ninject), HttpRequest, UnitOfWork & attivazione contestuale

rated by 0 users
This post has 7 Replies | 2 Followers

Top 25 Partecipanti
Maschio
Post 30
Punteggio 678
neronotte Posted: 08-21-2010 14.37

Ciao a tutti,
da ieri pomeriggio sto sbattendo la testa con il seguente problema...

Contesto: applicazione web che consente l'avvio, in modalità asincrona, di procedure (Job) verso un sistema esterno. Uso Ninject come IoC provider.

L'interazione con il sistema esterno avviene tramite un SKD proprietario. Ogni interazione con il sistema esterno deve essere effettuata all'interno di una UnitOfWork, che può essere "attivata" in due modalità: 

  • Modalità 1: accedo con le credenziali dell'utente che ha lanciato la mia applicazione web. Tramite la UoW posso leggere/scrivere soltanto i dati su cui l'utente ha effettivamente visibilità (i privilegi sono gestiti sul sistema esterno)
  • Modalità 2: accesso tramite admin. In questo modo posso leggere/scrivere tutti i dati presenti nel sistema.

Io ho i tutti i miei bei repository, che agganciati alla UoW, mi consentono di recuperare i dati di cui ho bisogno dal sistema esterno, e salvare le modifiche ad essi apportate.

Quando l'utente accede alla mia applicazione, deve poter vedere una maschera contenente una serie di campi alimentati con tutte e sole le entità di tipo Foo, lette dal sistema esterno, su cui lui ha visibilità. Tramite questa maschera, può scegliere i parametri di avvio del Job e lanciarlo. Il job sarà avviato in un thread secondario (tramite un Task); per funzionare correttamente, il job ha bisogno di poter "vedere" tutti i dati presenti nel sistema esterno.

Avrei dunque bisogno che:

  • le istanze dei repository utilizzate per riempire i campi della pagina di avvio del job fossero agganciati ad una sessione inizializzata in modalità 1, mentre 
  • le istanze dei repository utilizzate dal mio job fossero agganciate ad una sessione inizializzata in modalità 2...

(nel primo caso, avrei bisogno che venisse creata una nuova sessione ad ogni richiesta HTTP. Nel secondo caso, deve essere creata una nuova sessione per ogni run del job).

Come posso fare? Qualche idea? 

Grazie,
neronotte

Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
Ciao neronotte,

neronotte wrote:
> Ciao a tutti,
> da ieri pomeriggio sto sbattendo la testa con il seguente problema...
[cut]

Tornare dalle ferie e trovare 'sta roba nel reader NNTP non ha prezzo. :-)
Dal basso della mia ignoranza, sto ragionando sul problema ma... ancora
non sono venuto a capo di nulla.

Ciao,
petrux - De Vliegende Hollander

--
  • | Punteggio Post: 5
Top 10 Partecipanti
Post 143
Punteggio 2.560
Ciao neronotte,

You wrote on 21/08/2010 :
> Avrei dunque bisogno che:le istanze dei repository utilizzate per riempire i
> campi della pagina di avvio del job fossero agganciati ad una sessione
> inizializzata in modalit� 1, mentre le istanze dei repository utilizzate dal
> mio job fossero agganciate ad una sessione inizializzata in modalit� 2...
> (nel primo caso, avrei bisogno che venisse creata una nuova sessione ad ogni
> richiesta HTTP. Nel secondo caso, deve essere creata una nuova sessione per
> ogni run del job).Come posso fare? Qualche idea?

io farei cos�: invece di far dipendere i repository direttamente dalla
sessione li fari dipendere da una sorta di ISessionProvider:

interface ISessionProvider
{
ISession GetAdminSession( Credential ... );
ISession GetCurrentUserSession();
}

� sostenibile?

..m

--
Mauro Servienti
{C67C0157-5D98-4733-A75E-93CAEE4BADC8}
Microsoft MVP - Visual C# / MCTS
http://mvp.support.microsoft.com
blog @ http://milestone.topics.it
whynot [ at ] topics [ dot ] it
  • | Punteggio Post: 20
Top 25 Partecipanti
Maschio
Post 30
Punteggio 678

Ciao Mauro,

effettivamente nel descrivere la soluzione ho "semplificato" un po' le cose: attualmente i repository ereditano già da un session provider fatto più o meno così:

public interface ISessionProvider
{
    ISession GetSession();


la classe base, generica, Repository<T> espone una proprietà protected Session:

public abstract class Repository<T> : IRepository<T>
{
...
    protected ISession Session { get { return this.sessionProvider.GetSession(); } }
...
}

se utilizzassi il sessionProvider che mi hai consigliato, non violerei il SRP? Intendo... a quel punto diventerebbe compito del repository decidere quale tipo di sessione utilizzare, o sbaglio?

E se sia il job che la pagina utilizzassero lo stesso "tipo" di repository? (Entrambi avranno bisogno dello UserRepository, per dirne una...)

Grazie :)
neronotte 

  • | Punteggio Post: 20
Top 10 Partecipanti
Post 143
Punteggio 2.560
Ciao neronotte,

You wrote on 25/08/2010 :
> se utilizzassi il sessionProvider che mi hai consigliato, non violerei il
> SRP? Intendo... a quel punto diventerebbe compito del repository decidere
> quale tipo di sessione utilizzare, o sbaglio?

si sono abbastanza d'accordo, violeresti violeresti :-)
Non so come funzioni Ninject ma ad esempio con Castle potresti
esternalizzare quella decisione e spostarla nel container utilizzando
svariate tecniche, alcuni per� sostegono che sposti una responsabilit�
applicativa (aka logica di business) al di fuori della logice di
business.

Non saprei... probabilmente in entrambi i casi non � la scelta
migliore, ma in un modo o nell'altro dei farla funzionare :-)

..m

--
Mauro Servienti
{C67C0157-5D98-4733-A75E-93CAEE4BADC8}
Microsoft MVP - Visual C# / MCTS
http://mvp.support.microsoft.com
blog @ http://milestone.topics.it
whynot [ at ] topics [ dot ] it
  • | Punteggio Post: 5
Top 10 Partecipanti
Post 143
Punteggio 2.560
incuriosito mi sono letto un po' di documentazione di Ninject e mi
chiedo: perch� non implementi un IProvider

http://wiki.github.com/ninject/ninject/providers-factory-methods-and-the-activation-context

e sfrutti il call context (IContext) per prendere la dicione corretta
in fase di risoluzione?

..m

--
Mauro Servienti
{C67C0157-5D98-4733-A75E-93CAEE4BADC8}
Microsoft MVP - Visual C# / MCTS
http://mvp.support.microsoft.com
blog @ http://milestone.topics.it
whynot [ at ] topics [ dot ] it
  • | Punteggio Post: 20
Top 25 Partecipanti
Maschio
Post 30
Punteggio 678

Ciao Mauro,

c'ho provato... il problema resta nella gestione del lifecycle delle diverse session: la sessione aperta in modalità 1 deve durare quanto la request, mentre la sessione in modalità 2 deve durare quanto un run del job. I provider, a quanto sembra dalle prove che ho fatto, vengono "valutati" soltanto alla prima richiesta dell'oggetto "provisionato" all'interno dello scope definito in fase di configurazione (l'HttpContext corrente, nel caso della modalità 1), dopodichè ninject "cacha" il valore ottenuto dal provider agganciandolo in qualche modo all'oggetto che definisce lo scope, e continua a restituire la medesima istanza finquando questo non viene processato dal garbage collector.

Temo che l'unica via per uscirne sia avere due Kernel distinti, uno per il modulo "Web", e l'altro per il modulo di processamento dei job... 

...e la cosa non mi piace per niente.

Altre idee?

Grazie,
neronotte 

  • | Punteggio Post: 20
Top 10 Partecipanti
Post 143
Punteggio 2.560
Ciao neronotte,

You wrote on 25/08/2010 :
> ...e la cosa non mi piace per niente.Altre idee?

non ho idea di come funzioni Ninject quindi ci sta eccome :-)
Neanche a me piace il doppio Kernel ma mi sembra la soluzione pi�
semplice e a minor costo.

..m

--
Mauro Servienti
{C67C0157-5D98-4733-A75E-93CAEE4BADC8}
Microsoft MVP - Visual C# / MCTS
http://mvp.support.microsoft.com
blog @ http://milestone.topics.it
whynot [ at ] topics [ dot ] it
  • | Punteggio Post: 5
Pagina 1 di 1 (8 elementi) | RSS
Powered by Community Server (Commercial Edition), by Telligent Systems