2010-07-20 13 views
9

Tengo problemas para obtener 2 aplicaciones idénticas de ASP.NET MVC para compartir la misma sesión utilizando un Session StateServer. La razón por la que trato de hacer esto es que finalmente implementaremos esta aplicación en 3 servidores web que necesitan compartir el mismo estado. Necesitamos usar StateServer porque estamos tratando de minimizar el uso de la base de datos para el almacenamiento no relacionado con los datos.¿Por qué no puedo compartir el estado de sesión entre 2 aplicaciones web con StateServer? ¿Qué me estoy perdiendo?

El programa de instalación:

He desplegado el mismo código base a http://localhost/App1 y http://localhost/App2

ambos tienen archivos Web.Config idénticos con lo siguiente:

<system.web> 
<sessionState mode="StateServer" 
       cookieless="false" 
       timeout="20" 
       stateConnectionString="tcpip=127.0.0.1:42424" /> 
       //stateConnectionString="tcpip=192.168.1.52:42424" /> // also doesn't work 
<machineKey 
    validationKey="8B9F68D0CC730F6F046D0173021C34B1A0D9A01C21D8E4D4A7A1DFF38332DEE8CBBAFEA503C18776614EE9D4F7EEA7E5D2D5571630547D822485A27B1EF53AC1" 
    decryptionKey="60009563EFCFC594FD1BC46684943AA398EE70412A624B2EB488BBB071F15ECF" 
    validation="SHA1" decryption="AES" /> 

He usado this tool to generate these machine keys

La prueba:

puse lo siguiente en uno de mis controladores para probar si funcionaba:

ViewData["mode"] = requestContext.HttpContext.Session.Mode.ToString(); 

string timestamp = DateTime.Now.ToString(); 
if (requestContext.HttpContext.Session["timestamp"] == null) 
{ 
    requestContext.HttpContext.Session["timestamp"] = timestamp; 
} 

ViewData["timestamp"] = requestContext.HttpContext.Session["timestamp"].ToString(); 
ViewData["realtime"] = timestamp; 

con esto en la vista:

<p> 
    Mode: <%= ViewData["mode"].ToString() %> 
</p> 
<p> 
    Time: <%= ViewData["timestamp"].ToString() %> 
</p> 
<p> 
    real time: <%= ViewData["realtime"].ToString() %> 
</p> 

El resultado:

Para ambas implementaciones, cuando la página se carga por primera vez, veo que el modo es StateServer y la marca de tiempo se establece en el mismo tiempo que el valor en tiempo real. Sin embargo, si esto funcionaba, solo la primera página debería tener el mismo tiempo. como el valor en tiempo real. La carga de la segunda página debe leer del StateServer porque el valor de la marca de tiempo ya no es nulo y muestra ese valor de tiempo. Pero, en cambio, muestra el valor en tiempo real de nuevo.

Cuando actualizo la página, la marca de tiempo permanece igual y el valor en tiempo real siempre se actualiza. Esto indica que la marca de tiempo se está guardando en la sesión, pero el valor del sello de tiempo siempre es diferente para ambas implementaciones cuando debería ser el mismo, por lo que esto indica que la sesión no se está compartiendo.

¿Alguien puede señalar si estoy haciendo algo mal o si hay algo más que tengo que hacer para que esto funcione? Gracias

+0

¿Pudo completar esto ? –

+0

@DaveDev Sé que llego tarde a la fiesta: P, pero esto podría ayudar a otros. si pudieras encontrar lejos para compartir el mismo dominio para la cookie de sesión (ver https://msdn.microsoft.com/en-IN/library/ms228262(v=vs.85).aspx) y almacenar la sesión en el servicio común (DB/Redis) entonces usted puede compartir la sesión entre el servidor múltiple –

Respuesta

10

De manera predeterminada, la sesión no se puede compartir entre diferentes aplicaciones. Por lo que puedo ver, tiene dos aplicaciones distintas App1 y App2 que se ejecutan en directorios virtuales separados y probablemente incluso en grupos de aplicaciones separados, por lo que no espera compartir sesión entre ellos.

Como siempre, hay workarounds que pueden serle de utilidad. Como puede ver, está utilizando un truco (reflejo) para eludir la determinación del diseñador del equipo ASP.NET de no exponer ciertas clases y propiedades y hacer que nuestra vida como desarrolladores sea difícil.

+0

Tiene razón en que son aplicaciones distintas. Existe uno en D: \ App1 y el otro en D: \ App2, y se encuentran en directorios virtuales diferentes en DefaultWebSite en IIS. Sin embargo, ambos están en DefaultAppPool. La razón de esto es que finalmente implementaremos esta aplicación en 3 servidores web que necesitan compartir el mismo estado. – DaveDev

+0

Creo que es el directorio virtual que determina el nombre de la aplicación y no el grupo de aplicaciones, así que supongo que tendrá que recurrir a la corte que obliga el mismo nombre de la aplicación. –

+0

Ok, tomaré esto en consideración. Si terminamos yendo por la ruta de los hacks para lograr este resultado, creo que sería mejor que nos quedáramos con la base de datos para almacenar la sesión. El enfoque db parece ser más robusto de todos modos. – DaveDev

2

Actualización: Aquí es un post anterior respondí en este tema Sharing sessions across applications using the ASP.NET Session State Service

Como ya se ha señalado, los datos de sesión está en el ámbito de la aplicación. Esa es la Aplicación que creaste en IIS.Por lo tanto, dos aplicaciones con la misma ID de sesión no compartirán la misma sesión debido al alcance de la aplicación.

Como una idea alternativa que podría o no ser factible para usted. Puede crear una aplicación raíz y tener el código para D: \ App1 y D: \ App2 en dos subcarpetas.

d:\Root 
    web.config 
    \App1 
    default.aspx 
    ... 
    \App2 
    default.aspx 
    ... 

Luego en IIS crea una Aplicación que apunta a d: \ Root.

También puede crear una Aplicación en IIS y luego en la Aplicación crea dos directorios virtuales, uno apuntando a D: \ App1 y el otro a D: \ App2, luego también pueden compartir un solo web.config en la Aplicación nivel. Es fundamental que los dos directorios virtuales sean simplemente virtuales y no se creen como Aplicaciones.

Así que el diseño del disco duro podría ser algo como esto

D:\Root 
    web.config 

D:\App1 
    default.aspx 
    ... 

D:\App2 
    default.aspx 
    ... 

Cree la aplicación de la raíz que apunta a D: \ Root y luego bajo la aplicación crear los dos directorios virtuales App1 apuntando a D: \ App1 y App2 señalador a D: \ App2.

El efecto en ambos casos es que realmente tiene una aplicación dividida en dos secciones, ambas en el mismo ámbito de sesión, por lo que el código para ambas puede compartir los mismos datos de sesión.

2

También debe asegurarse de que la ruta de la aplicación debe ser la misma en ambos servidores web. Hay un viejo artículo aquí que podría ayudar

http://support.microsoft.com/default.aspx?scid=kb;EN-US;q325056

Actualmente estamos experimentando un problema similar, excepto que estamos utilizando IIS 7.5 y las rutas de aplicaciones están ocultas para nosotros (no utiliza el metabase ya no). ¿Alguien sabe una forma de solucionar este problema con IIS 7.5?

+0

En mi opinión, creo que Microsoft dejó caer la pelota con IIS en el último par de versiones. – DaveDev

5

Actualmente, puede compartir sesiones utilizando el modo de servidor Sql.

Prueba esto: -

simplemente he cambiado el procedimiento es decir

USE ASPState 
GO 

ALTER PROCEDURE dbo.TempGetAppID 
    @appName tAppName, 
    @appId int OUTPUT 
AS 

    -- start change 

    -- Use the application name specified in the connection for the appname if specified 
    -- This allows us to share session between sites just by making sure they have the 
    -- the same application name in the connection string. 
    DECLARE @connStrAppName nvarchar(50) 
    SET @connStrAppName = APP_NAME() 

    -- .NET SQLClient Data Provider is the default application name for .NET apps 
    IF (@connStrAppName <> '.NET SQLClient Data Provider') 
     SET @appName = @connStrAppName 

    -- end change 

SET @appName = LOWER(@appName) 
SET @appId = NULL 

SELECT @appId = AppId 
FROM [ASPState].dbo.ASPStateTempApplications 
WHERE AppName = @appName 

IF @appId IS NULL BEGIN 
BEGIN TRAN 

SELECT @appId = AppId 
FROM [ASPState].dbo.ASPStateTempApplications WITH (TABLOCKX) 
WHERE AppName = @appName 

IF @appId IS NULL 
BEGIN 
EXEC GetHashCode @appName, @appId OUTPUT 

INSERT [ASPState].dbo.ASPStateTempApplications 
VALUES 
(@appId, @appName) 

IF @@ERROR = 2627 
BEGIN 
DECLARE @dupApp tAppName 

SELECT @dupApp = RTRIM(AppName) 
FROM [ASPState].dbo.ASPStateTempApplications 
WHERE AppId = @appId 

RAISERROR('SQL session state fatal error: hash-code collision between applications ''%s'' and ''%s''. Please rename the 1st application to resolve the problem.', 
18, 1, @appName, @dupApp) 
END 
END 

COMMIT 
END 

RETURN 0 
GO 

y luego modificado web.config como: -

<sessionState mode="SQLServer" sqlConnectionString="Data Source=.;Integrated Security=True;Application Name=TEST" cookieless="false" timeout="20"></sessionState> 
    <httpRuntime targetFramework="4.5"/> 

hay que añadir Nombre de la aplicación y que tienen ser el mismo para todas las aplicaciones para las que desea compartir la misma sesión.

Gracias.

+0

esto realmente funcionó :) –

+0

No solo funcionó, sino que es la implementación más fácil de lejos. ¡Gracias! –

+0

También asegúrese de que las claves de su máquina y las identificaciones de la aplicación sean las mismas. https://blogs.msdn.microsoft.com/httpcontext/2012/06/22/shared-session-state-in-a-iis6-and-iis7-web-farm/ –

Cuestiones relacionadas