144 messaggi dal 26 febbraio 2007
Ciao,

Ho una variabile in cui salvo alcuni dati che è dichiarata come Scoped.

Ho notato che se da postman faccio due chiamate a due servizi diversi (nello stesso momento), è come se i valori di questa variabile scoped fossero modificati dalla prima chiamata.

Ma essendo due chiamate diverse, non dovrebbero avere scoped separati? mi aspetterei questo comportamento da un Singleton, perchè allora lanciando due chiamate in contemporanea mi capita questo?


Grazie mille
11.886 messaggi dal 09 febbraio 2002
Contributi

Ma essendo due chiamate diverse, non dovrebbero avere scoped separati?


Sì, ogni richiesta riceve senz'altro una propria istanza del servizio che hai registrato con AddScoped.
Non so perché tu abbia l'impressione che stiano interferendo l'una con l'altra. Forse hai dei campi static all'interno, non so. Dovresti postare un po' di codice.

Per verificare che si tratti effettivamente di due istanze diverse, fai un:
Console.WriteLine($"Hash code dell'istanza: {tuaVariabile.GetHashCode()}");


ciao,
Moreno

Enjoy learning and just keep making
144 messaggi dal 26 febbraio 2007
Ho capito dove sta il problema, adesso devo cercare di capire il motivo :)



Ho dichiarato il middleware

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseWhen(context => context.Request.Path.StartsWithSegments("/api/Auth"), appBuilder =>
            {
                appBuilder.UseMiddleware(typeof(AuthMiddleware));
            });



Questo è il codice del middleware

public class AuthMiddleware
{
  readonly RequestDelegate _next;
  readonly AuthAppConfig _config;
  readonly PolicyDecisionPointManager _policyDecision;
  IAuthManager _authManager;
  readonly ISTLogger _logger;

  public AuthMiddleware(RequestDelegate next, IOptions<AuthAppConfig> config, IHostingEnvironment env)
  {
    _logger = STLoggerFactory.Logger;
    _next = next;
    _config = config.Value;
    _policyDecision = new PolicyDecisionPointManager(env, _logger);
  }

  public async Task Invoke(HttpContext httpContext, IUserData _userData)
  {
    _authManager = new AuthBasicManager(_config, _userData, _logger);
  }
}




Dichiaro la classe AuthBasicManager


    public class AuthBasicManager : IAuthManager
    {
        private readonly IUserData _userData;

        public AuthBasicManager(AuthAppConfig config, IUserData userData, ISTLogger logger)
        {
            _userData = userData;
        }




Facendo così il valore GUID che ho isnerito nella classe userData dentro la classe AuthMiddleware è sempre quello corretto.
Invece nella classe AuthBasicManager rimane sempre e solo memeorizzato la userData della prima chiamaata (il guid che ho inserito per tenere traccia è sempre quello).


Se invece nel middleware cambio da

_authManager = new AuthBasicManager(_config, _userData, _logger);

a

IAuthManager _authManager = new AuthBasicManager(_config, _userData, _logger);


Ovvero questa variabile è usata solo nell'Invoke e non memeorizzata nella classe allora tutto funziona correttamente.


Mi sfugge qualcosa nel flusso delle chiamate, probabilmente la classe middleware viene instanziata solo la prima volta, però la invoke dovrebbe ridichiararmi la _authManager... e non capisco... però il problema è proprio in questo punto
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,


IAuthManager _authManager = new AuthBasicManager(_config, _userData, _logger);

Ok, bene così. Credo che questa sia la soluzione definitiva. A parte questo, sei sicuro di voler usare un tuo oggetto IUserData anziché valorizzare la proprietà User dell'HttpContext che è già lì a questo scopo?


la invoke dovrebbe ridichiararmi la _authManager... e non capisco... però il problema è proprio in questo punto

Non puoi fare affidamento sull'ordine in cui arrivano le richieste perché possono essere elaborate out-of-order. ASP.NET Core ha un pool di thread che lavorano contemporaneamente e non puoi sapere a priori quando verranno di fatto posti in esecuzione dal sistema operativo. Magari concede la priorità al thread della seconda richiesta... chi lo sa. E oltretutto il metodo Invoke del middleware non è thread safe. Può esserti invocato da due thread differenti e se vai a insistere su un campo privato del middleware potrebbero succedere disastri se viene scritto contemporaneamente.

In sintesi: non dovresti indagare oltre sul perché stai osservando quel comportamento perché gli effetti sono imprevedibili e comunque è una cosa da non fare.

ciao,
Moreno
Modificato da BrightSoul il 14 marzo 2019 08:39 -

Enjoy learning and just keep making
144 messaggi dal 26 febbraio 2007
Grazie mille per le risposte.

Mi stava sfuggendo che il Middleware era instanziato all'avvio e non ad ogni richiesta, quindi io con 2 richieste andavo a modificare una classe privata che in realta era condivisa tra più richieste.


Quindi spostandola dentro l'invoke, ogni richiesta avrà la sua istanza della variabile.


Utilizzo UserData perchè al suo interno ha una struttura di informazioni complessa, che non riesco a gestire con i Claims.
11.886 messaggi dal 09 febbraio 2002
Contributi

Utilizzo UserData perchè al suo interno ha una struttura di informazioni complessa, che non riesco a gestire con i Claims.


Ok, non so come funzionerà la tua parte di autorizzazione ma non dovresti rinunciare a usare l'attributo Authorize e le policy di ASP.NET Core, perché sono molto potenti e facili da usare.
Potresti provare a crearti una classe che implementa IUserData ma che deriva anche da ClaimsPrincipal. In questo modo la puoi settare su User ma puoi anche aggiungere a piacimento altre proprietà complesse. Così ti semplifichi il problema almeno per quanto riguarda l'autorizzazione.

ciao,
Moreno

Enjoy learning and just keep making
144 messaggi dal 26 febbraio 2007
Giusto, non avevo pensato a questa soluzione, lo cambio subito in questo modo.

Grazie :)
144 messaggi dal 26 febbraio 2007
Avrei una piccola domanda aggiuntiva per quanto riguarda i Claims.

Per quanto riguarda l'autenticazione sulla mia webapi utilizzo JwtBearer. Quindi tutte le info sui Claims assegnati, vengono inseriti nel Token generato.

Se però un utente amministratore dovesse modificare un permesso all'utente loggato (quindi di conseguenza dovessi eliminare\aggiungere) un claim, dovrei per forza generare un nuovo JwtBearer, non c'è modo di modificare il Token in possesso del client aggiungendo il nuovo Claim (perchè in questo caso il Token assumerebbe un altro valore), giusto?

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.