2012-05-04 18 views
8

Estoy construyendo una aplicación MVC3 utilizando el marco de Ninject. Tengo un servicio que me lleva mucho tiempo inicializar, y al final este servicio tendrá un objeto que contiene información específica del usuario, entonces necesito reutilizar ese servicio siempre y cuando la sesión del usuario esté activa, de modo que puede evitar inicializar ese servicio una y otra vezNinject concepto de alcance de sesión en MVC3

así que mi pregunta es

Cuando ato el servicio mediante Ninject qué tipo de alcance debería recoger, no hay ninguna sesión por el alcance de Ninject, así que cuál es la mejor forma de implementar el requisito? o fui en una dirección equivocada?

He creado un proveedor personalizado para uno de mis servicios que creará el servicio en función de los datos del nombre de usuario que se toma del actual Controller.User.Identity.Name. El siguiente código no funcionará porque falta la variable local userName, ¿cómo puedo pasar el valor del nombre de usuario a mi proveedor personalizado a través de Ninject, para que pueda recogerlo desde IContext?

public class TfsConnectionManagerProvider : Provider<TfsConnectionManager> 
    { 
     protected override TfsConnectionManager CreateInstance(IContext context) 
     { 
      Uri serverUri = new Uri(ConfigurationHelper.TfsServerUrl); 
      // Connect to the server without impersonation 
      using (TfsTeamProjectCollection baseUserConnection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(serverUri)) 
      { 
       // Get the identity management service 
       IIdentityManagementService ims = baseUserConnection.GetService<IIdentityManagementService>(); 

       // Get the identity to impersonate 
       TeamFoundationIdentity identity = ims.ReadIdentity 
       (
        IdentitySearchFactor.AccountName, 
        userName, //NOTE: How can I get user name value from IContext??? 
        MembershipQuery.None, 
        ReadIdentityOptions.None 
       ); 

       // Connect using the impersonated identity 
       using (TfsTeamProjectCollection impersonatedConnection = new TfsTeamProjectCollection(serverUri, identity.Descriptor)) 
       { 
        WorkItemStore store = impersonatedConnection.GetService<WorkItemStore>(); 

        return new TfsConnectionManager 
        { 
         Store = store 
        }; 
       } 
      } 
     } 
    } 
+0

Ver también http: // stackoverflow.com/questions/4687707/ninject-per-session-singleton –

Respuesta

2

Aparece el uso de un proveedor personalizado para crear la instancia y en el proveedor personalizado que comprobé si existe sesión o no.

La unión se realiza de la siguiente manera

Bind<IRepository>().ToProvider(new TfsRepositoryProvider()); 

El proveedor personalizado está por debajo

public class TfsRepositoryProvider : Provider<TfsRepository> 
    { 
     private const string SesTfsRepository = "SES_TFS_REPOSITORY"; 

     protected override TfsRepository CreateInstance(IContext context) 
     { 
      // Retrieve services from kernel 
      HttpContextBase httpContext = context.Kernel.Get<HttpContextBase>(); 

      if (httpContext == null || httpContext.Session == null) 
      { 
       throw new Exception("No bind service found in Kernel for HttpContextBase"); 
      } 

      return (httpContext.Session[SesTfsRepository] ?? (
        httpContext.Session[SesTfsRepository] = new TfsRepository(context.Kernel.Get<IWorkItemStoreWrapper>())) 
       ) as TfsRepository; 
     } 
    } 
0

bien, se puede almacenar en caché/almacenar la información del usuario en su aplicación y sólo llamar al servicio externo si usted no tiene (reciente) la información del usuario. En su "capa" de recuperación de información de usuario, solo programa esas dos posibilidades.

Donde caché, depende totalmente de usted. Puede almacenar esta información, por ejemplo, en una base de datos local.

Aparentemente te entendí mal, mis disculpas (debajo de mi respuesta original).

Se puede utilizar, por ejemplo, una fábrica (resumen) que tiene un miembro estático de su servicio (por ejemplo) por lo que se volverá a utilizar.

Aunque dependiendo de su servicio, esto podría tener algunos efectos secundarios no deseados (lo hice esta vez con los servicios de datos y en un contexto de mis datos aplicación ASP.NET MVC3 se atornilla un poco debido a una cierta magia que ocurrió ). Todo lo que quiero decir con esto es: tenga cuidado y pruébelo bien.

+0

Disculpe, quizás no explique bien mi pregunta, la inicialización del servicio implica llamadas a algunos servicios web que luego devolverán información específica del usuario. No puedo hacer que sea estático porque es específico del usuario – Ming

+0

Ow, entonces te malentendí :). Lo que puede hacer es intentar almacenar en caché los datos del usuario (información) en su aplicación, y solo debe llamar a los servicios externos si no tiene la información del usuario usted mismo. – Styxxy

+0

Sí, así que llega a mi verdadera pregunta anterior: ¿cómo puedo lograrlo a través de enlace Ninject utilizando el alcance – Ming

7

Un alcance de sesión no se ofrece intencionalmente en Ninject, porque tener servicios en un estado de sesión es incorrecto en casi cualquier situación. Debe tener mucho cuidado con el uso del estado de la sesión porque trae muchas desventajas.

Trate de tener una aplicación sin estado en primer lugar.

Si hay una buena razón para tener datos en el alcance de la sesión, coloque esos datos (no los servicios) en el estado de sesión y use servicios que estén en singleton, transitorio o solicite alcance para el procesamiento (separación de datos y funcionalidad)

+0

Gracias Remo, podría ser confuso que puse la sesión en mi descripción original. No me refiero a que iba a usar la sesión para guardar los datos, el objetivo es reutilizar tanto como sea posible el objeto específico del usuario que regresó del servicio de larga ejecución con el marco de Ninject. Cualquier idea de diseño apropiada será bienvenida – Ming