¿Qué se necesita en el HttpContext para permitir que FormsAuthentication.SignOut () se ejecute?

StackOverflow https://stackoverflow.com/questions/1430180

  •  07-07-2019
  •  | 
  •  

Pregunta

Estoy tratando de escribir una prueba unitaria para nuestro método de desconexión. Entre otras cosas, FormsAuthentication.SignOut () . Sin embargo, arroja un System.NullReferenceException .

He creado un simulacro; HttpContext (usando Moq), pero obviamente le falta algo.

Mi contexto simulado contiene:

  • Un HttpRequestBase burlado en Request
  • Un HttpResponseBase burlado en Response
  • Con una HttpCookieCollection en Request.Cookies y otra en Response.Cookies
  • Un IPrincipal burlado en User

Soy consciente de que podría seguir la ruta del contenedor e inyectar un objeto contenedor vacío FormsAuth en su lugar, pero realmente me gustaría evitar los 3 archivos adicionales solo para arreglar una línea de código. Eso y todavía tengo curiosidad por una respuesta

Entonces mi pregunta es " Qué se necesita en el HttpContext para permitir que FormsAuthentication.SignOut () se ejecute. "

¿Fue útil?

Solución

Aquí está el código para cerrar sesión.

public static void SignOut()
{
    Initialize();
    HttpContext current = HttpContext.Current;
    bool flag = current.CookielessHelper.DoesCookieValueExistInOriginal('F');
    current.CookielessHelper.SetCookieValue('F', null);
    if (!CookielessHelperClass.UseCookieless(current, false, CookieMode) || current.Request.Browser.Cookies)
    {
        string str = string.Empty;
        if (current.Request.Browser["supportsEmptyStringInCookieValue"] == "false")
        {
            str = "NoCookie";
        }
        HttpCookie cookie = new HttpCookie(FormsCookieName, str);
        cookie.HttpOnly = true;
        cookie.Path = _FormsCookiePath;
        cookie.Expires = new DateTime(0x7cf, 10, 12);
        cookie.Secure = _RequireSSL;
        if (_CookieDomain != null)
        {
            cookie.Domain = _CookieDomain;
        }
        current.Response.Cookies.RemoveCookie(FormsCookieName);
        current.Response.Cookies.Add(cookie);
    }
    if (flag)
    {
        current.Response.Redirect(GetLoginPage(null), false);
    }
}

Parece que necesita una instancia de CookielessHelperClass. Lástima que sea interno y esté sellado: no hay forma de burlarse de él a menos que esté usando TypeMock. +1 para sugerencias de envoltura :)

Otros consejos

La excepción NullReferenceException en este caso en realidad está siendo lanzada por la llamada:

current.Request.Browser["supportsEmptyStringInCookieValue"]

Puede probar esta afirmación llamando:

HttpContext.Current.Request.Browser.SupportsEmptyStringInCookieValue

... que también devolverá la NullReferenceException. Contrariamente a la respuesta aceptada, si intenta llamar:

CookielessHelperClass.UseCookieless(current, false, CookieMode)

... desde la ventana inmediata, esto volverá sin error.

Puede solucionar la excepción de esta manera:

HttpContext.Current.Request.Browser = new HttpBrowserCapabilities() { Capabilities = new Dictionary<string, string> { { "supportsEmptyStringInCookieValue", "false" } } };

... y la llamada FormsAuthentication.SignOut () ahora tendrá éxito.

Siempre puedes envolver FormsAuthentication.SignOut () en otro método y ponerlo / simularlo.

Crear interfaz IFormsAuthenticationWrap.

public interface IFormsAuthenticationWrap
{
    void SignOut();
}

Crear clase de ajuste que implemente IFormsAuthenticationWrap

public class FormsAuthenticationWrap : IFormsAuthenticationWrap
{
    public void SignOut()
    {
        FormsAuthentication.SignOut();
    }
}

Tu clase de llamada se verá así:

public class LogOutClass
{
    private readonly IFormsAuthenticationWrap _formsAuthentication;

    public LogOutClass() : this (new FormsAuthenticationWrap())
    {
    }

    public LogOutClass(IFormsAuthenticationWrap formsAuthentication)
    {
        _formsAuthentication = formsAuthentication;
    }

    public void LogOutMethod()
    {
        // Code before SignOut

        _formsAuthentication.SignOut();

        // Code after SignOut
    }
}

Ahora vamos a nuestra prueba. Puede tropezar / burlarse de Moq, pero aquí le mostraré cómo puede hacerlo manualmente. Cree su clase stub / simulacro:

public class FormsAuthenticationStub : IFormsAuthenticationWrap
{
    public void SignOut()
    {
    }
}

Y el último escribe la prueba:

    [TestMethod]
    public void TestLogOutMethod()
    {
        var logOutClass = new LogOutClass(new FormsAuthenticationStub());
        logOutClass.LogOutMethod();
    }

El contenedor es el camino limpio a seguir.

Usted mencionó en un comentario que "esta va a ser una aplicación bastante grande", ese es otro argumento para usar el contenedor, no al contrario. En una aplicación grande, desea tener dependencias claras y desea que las pruebas se realicen fácilmente.

Usted está intercambiando dependencias limpias que pueden inyectarse fácilmente sobre dependencias oscuras al funcionamiento interno de asp.net en sus pruebas.


En una nota diferente: Usar Reflector . Sinceramente, no conozco las dependencias internas de esta parte específica de asp.net, pero puede aclarar cualquier duda con reflector.

No te burles de HttpContext, usa uno real en tus pruebas. De esta manera no tienes que burlarte de todas estas cosas Http *. Puede usar Ivonna y probar su método directamente, sin burlarse de todas estas dependencias y obtener misteriosas excepciones.

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