Domanda

Ho un servizio WCF che utilizza un usernamePasswordValidator personalizzato. Il validatore deve accedere al mio contesto quadro di entità.

Vorrei creare un oggettoContext per l'intera chiamata di servizio e quindi distruggerla / smaltirlo alla fine della chiamata. Così ho creato una classe statica Singleton che ha fornito questa funzionalità, tuttavia, cosa sta succedendo ora è che se due chiamate di servizio accadono contemporaneamente, una delle chiamate dispone del singleton.

I mantengo un riferimento locale all'oggettoContext, nel qual caso il secondo servizio di usarlo lo vede come smaltito e lanciare ed errori, o, ho messo una proprietà in wrapper attorno alla classe Singleton ovunque ne abbia bisogno e poi tutto il mio Le modifiche vengono gettate via perché sto ottenendo una nuova istanza dell'oggetto se un'altra chiamata ha disposto.

Così fondamentalmente la mia domanda è come posso istanziare un oggettoContext per servizio di servizio?

Nota: l'istanza deve essere accessibile sia nel codice di servizio che nel codice personalizzato dell'immagineMepasswordValidator.

Non riesco a farlo nel costruttore o utilizzare un'istruzione utilizzando l'istruzione perché allora il personalizzato usernamepasswordValidator non ha accesso ad esso . C'è un modo per avere una classe statica per chiamata? Sembra impossibile, ma qual è il modo in giro? Dovrei cacciare l'oggetto in una sessione?

Il mio servizio è ospitato in IIS.

Aggiornamento:
Quindi ho inchiodato questo per memorizzare lo stato nel IstanceContext usando un oggetto IEXsion. Ma come posso accedere all'attuale InstanceContext in un usernamepasswordValidator?

È stato utile?

Soluzione

OK, quindi alla fine l'ho risolto utilizzando la seguente classe statica e facendo affidamento su ASP.NET per cache il contesto per me.

Non sono sicuro che questo sia il modo migliore per fare le cose, ma questo mi permette di usare un oggettoContext per richiesta, quindi non sto girando troppi e questo significa anche che non devo usare un bloccosull'oggetto che diventerebbe un incubo se molti utenti stavano usando il servizio.

public static class MyContextProvider
    {
        public static MyModel Context
        {
            get
            {
                if (HttpContext.Current.Items["context"].IsNull())
                {
                    HttpContext.Current.Items["context"] = new MyModel();
                }

                return HttpContext.Current.Items["context"] as MyModel;
            }
        }    
    }
.

Allora ovunque ho bisogno di un oggettoContext nell'app che chiamò

var context = MyContextProvider.Context;
.

Altri suggerimenti

Hai un'istanza per chiamata, hai anche 1 chiamata per esempio.

Quindi dovrebbe essere molto semplice, utilizzare un blocco using () { } nella toplevel del tuo metodo di messa a punto.

OK, ecco la classe con metodo statico per thread-safe che fornisce un singolo oggetto del modello di entità di oggettiContext per qualsiasi chiamata di servizio WCF e smaltirlo automaticamente alla fine della chiamata:

public static class EntityModelProvider
{
    private static readonly Dictionary<OperationContext, MyEntityModel> _entityModels = new Dictionary<OperationContext, MyEntityModel>();

    public static MyEntityModel GetEntityModel()
    {
        if (OperationContext.Current == null)
            throw new Exception("OperationContext is missing");

        lock (_entityModels)
        {
            if (!_entityModels.ContainsKey(OperationContext.Current))
            {
                _entityModels[OperationContext.Current] = new MyEntityModel();
                OperationContext.Current.OperationCompleted += delegate
                {
                    lock (_entityModels)
                    {
                        _entityModels[OperationContext.Current].Dispose();
                        _entityModels.Remove(OperationContext.Current);
                    }
                };
            }

            return _entityModels[OperationContext.Current];
        }
    }
.

Per il tuo servizio, è possibile specificare un comportamento del servizio che descritta la modalità di istanza del servizio:

[ServiceBehaviour(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService {
    ObjectContext context;
}
.

Un modo più pulito può essere quello di utilizzare il ServiceAuthenticationManager, che è in .NET 4.

http://msdn.microsoft.com/en -UR / Library / System.ServiceModel.ServiceAuthenticationManager.aspx

Dal metodo Authenticate (che override) è possibile accedere all'oggetto del messaggio e impostare le proprietà su di esso. Non l'ho usato in rabbia, quindi ymmv :)

Modifica Il problema con questo approccio è che non hai il nome utente e la password, quindi sarà comunque bisogno dell'autenticazione personalizzata.

Dai un'occhiata al usernamescurityTokenAuthenticator ... http:// msdn .microsoft.com / en-noi / biblioteca / system.IdentityModel.Selectors.UsernameSecityTokenAuthenticator (v= vs.90) .aspx


.

Ulteriore lettura dalla mia ricerca:

Le risposte a questa domanda forniscono alcuni suggerimenti su come usarlo:

Autenticazione WCF personalizzata con System.ServiceModel.ServiceAuthenticationManager? < / P >.

Se riesci a leggere (o ignorare) il russo, ho trovato suggerimenti utili a:

http://www.sql.ru/forum/actualthread.aspx ? TID= 799046

Questo articolo di progetti di codice piuttosto buono va oltre (crittografia e compressione e autorizzazione personalizzata)

http://www.codeproject .com / articoli / 165844 / WCF-client-server-application-with-personalizzato-autenti

Perché non passare nel contesto nel tuo cellulimento personalizzato quando si assegna al servizio: memorizza il contesto dell'oggetto nel validatore, e nel metodo di convalida sovrascritto lo nuovo se necessario.Quindi hai ancora accesso all'oggetto attraverso i servizi cutomusernamevalidator ..

A seconda di ciò che stai chiedendo: Crea la tua classe ObjectContext separata come oggetto dinamico: aggiungi che come proprietà a te personalizzato. Nel tuo validatore personalizzato - è ora possibile controllare se l'oggetto è disposto e crea nuovamente l'oggetto se necessario. Altrimenti se questo non è quello che stai cercando - basta archiviare il contesto nel validatore, hai ancora accesso sul lato server. Il codice qui è solo un'idea generalizzata - lo sto solo pubblicando come una cornice di riferimento in modo da poter avere un'idea di ciò di cui sto parlando.

public DynamicObjectContextObjectClass
{
  ObjectContext internalObjectContext;

}
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator
{

    public DynamicObjectContextObjectClass dynamiccontext;


    public override void Validate(string userName, string password)
    {
        if(dynamiccontext.internalObjectContext.isdisposed)
        {

        dynamiccontext.internalObjectContext = new Context;

            }
            try
            {
                if (string.IsNullOrEmpty(userName) || password == null)
                {
                    //throw new ArgumentNullException();
                    throw new FaultException("Username cannot be null or empty; Password cannot be null and should not be empty");
                }
       }
   }
} 
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top