Pregunta

Tengo un servicio WCF que está utilizando una costumbre UsernamePasswordValidator.El validador debe tener acceso a mi entity framework contexto.

Me gustaría crear una ObjectContext de la totalidad del servicio de llamadas y, a continuación, destruir o disponer de ella al final de la llamada.Así que he creado un singleton estático de la clase que proporciona esta funcionalidad, sin embargo, lo que está pasando ahora es que si dos llamadas de servicio de suceder al mismo tiempo, una de las llamadas dispone el singleton.

I mantener un local de referencia para la ObjectContext, en cuyo caso el segundo servicio se ve como eliminados y la arroja y error, o, puse un contenedor de propiedad alrededor de la clase Singleton donde se me necesite y, a continuación, todos mis cambios obtener tirado porque me estoy poniendo de una nueva instancia del objeto si otra llamada ha dispuesto de él.

Así que básicamente mi pregunta es ¿cómo puedo crear una instancia de una ObjectContext por llamada de servicio?

NOTA:La instancia debe ser accesible tanto en el código de servicio Y la costumbre UsernamePasswordValidator código.

No puedo hacer en el constructor o el uso de una instrucción de uso, porque entonces el personalizado UsernamePasswordValidator no tiene acceso a ella.Es allí una manera de tener una clase estática por llamada?Suena imposible, pero ¿cuál es la forma de evitar esto?Debo ser el almacenamiento en caché del objeto en una sesión?

Mi servicio está alojado en IIS.

ACTUALIZACIÓN:
Así que me he clavado hasta el estado de almacenamiento en la InstanceContext el uso de un IExtension objeto.Pero, ¿Cómo puedo acceder a la actual InstanceContext en un UsernamePasswordValidator?

¿Fue útil?

Solución

OK, así que al final lo resolví utilizando la siguiente clase estática y confiando en ASP.NET para cachear el contexto para mí.

No estoy seguro de si esta es la mejor manera de hacer las cosas, pero esto me permite usar un objetoContext por solicitud, así que no estoy girando demasiado y esto también significa que no tengo que usar un bloqueo.en el objeto que se convertiría en una pesadilla si muchos usuarios estaban usando el servicio.

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;
            }
        }    
    }

Luego, donde necesito un objetoContext en la aplicación, solo llame

var context = MyContextProvider.Context;

Otros consejos

Usted tiene una instancia por cada llamada, usted también tiene 1 llamada por ejemplo.

Así que debe ser muy simple, el uso de un using () { } bloque en el nivel superior de su OperationContract método.

OK, aquí está la clase con un método estático seguro de rosca que proporciona un objeto de modelo de entidad de objetos individuales para cualquier llamada de servicio WCF y lo dispare automáticamente al final de la llamada:

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];
        }
    }

Para su servicio, puede especificar un comportamiento de servicio que detalla el modo de instancia del servicio:

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

Una forma más limpia puede ser usar el ServiceAaThentationManager, que está en .NET 4.

http://msdn.microsoft.com/en -US / Library / System.Servicemodel.ServiceAuthenticationManager.aspx

del método Authenticate (que anulará) puede acceder al objeto de mensaje y establecer propiedades en él. No lo he usado enojado, por lo que YMMV :)

Editar el problema con este enfoque es que no tiene el nombre de usuario y la contraseña, por lo que aún necesitará la autenticación personalizada.

Echa un vistazo al UsernamesCurityTokenAuthenticator ... http:// msdn .Microsoft.com / es-EE. UU. / Library / System.IntityModel.selectors.UsernamesEcurityTokenAuthenticator (V= vs.90) .aspx


Lectura adicional de mi investigación:

Las respuestas a esta pregunta proporcionan algunas sugerencias sobre cómo usarla:

Autenticación de WCF personalizada con System.Servicemodel.serviceAuthenticationManager? < / p>

Si puede leer (o ignorar) al ruso, encontré sugerencias útiles en:

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

Este buen artículo de código de códigos, va más lejos (cifrado y compresión, así como autorización personalizada)

http://www.codeproject .com / Artículos / 165844 / WCF-Client-Server-Soplection-With-Custom-Authenti

¿Por qué no pasar en el contexto a su CustomValidator cuando le asigna al servicio: almacene su contexto de objeto en su validador y en el método de validación anulado en su nuevo lugar si es necesario.Luego aún tiene acceso al objeto a través de los servicios CutomusernAnameValidator ..

Dependiendo de lo que está preguntando: Cree su clase de ObjectContext separada como un objeto dinámico: agregue eso como una propiedad a usted personalizado. En su validador personalizado, ahora puede verificar si el objeto está dispuesto y vuelva a crear el objeto si es necesario. De lo contrario, si esto no es lo que está buscando, solo almacene el contexto en el validador, aún tiene acceso al lado del servidor. El código aquí es solo idea generalizada: solo lo estoy publicando como un marco de referencia para que pueda tener una idea de lo que estoy hablando.

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");
                }
       }
   }
} 

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top