gpt4 book ai didi

c# - 为什么 HttpContext 为空?

转载 作者:行者123 更新时间:2023-11-30 23:03:54 25 4
gpt4 key购买 nike

我刚刚阅读了不止一篇,但没有找到解决我问题的方法。我已经使用 FrameWork 4.5 创建了 WebApi + MVC 和单元测试项目。我有这个 HomeController.cs 用这个方法:

using Net.Personal.Authentication.FormAuthentication; 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;

namespace FormAuthenticationProva.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Title = "Home Page";

var guidAccount = "xxxxxxxx-xxxx-xxxx-xxxx-422632e0bd95";

var userData = new CookieUserData(guidAccount) { GuidAccount = guidAccount };

HttpContextBase httpContextBase = this.HttpContext;

AuthenticationProvider _authProvider = new AuthenticationProvider(httpContextBase.ApplicationInstance.Context);

_authProvider.CheckAuthorizationForUrl("http://pippo");

return View();
}
}
}

HomeControllerTest.cs 的代码如下:

using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FormAuthenticationProva.Controllers;
using Moq;
using System.Web;
using System.Collections.Specialized;
using System.Web.Routing;

namespace FormAuthenticationProva.Tests.Controllers
{
[TestClass]
public class HomeControllerTest
{
[TestMethod]
public void Index()
{ // Disposizione

var formData = new NameValueCollection { { "id", "test" } };
var request = new Mock<HttpRequestBase>();
request.SetupGet(r => r.Form).Returns(formData);
var context = new Mock<HttpContextBase>();
context.SetupGet(c => c.Request).Returns(request.Object);

var controller = new HomeController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);

// Azione
ViewResult result = controller.Index() as ViewResult;

// Asserzione
Assert.IsNotNull(result);
Assert.AreEqual("Home Page", result.ViewBag.Title);

}
}
}

AuthenticationProvider.cs 类在这里:

/* AuthenticationProvider.cs code */

using System;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Security;

namespace Net.Personal.Authentication.FormAuthentication
{
public class AuthenticationProvider : IFormsAuthentication
{
public AuthContextConfiguration AuthContextConfiguration { get; set; }

public AuthenticationProvider() {}
public AuthenticationProvider(HttpContext context , AuthContextConfiguration authContextConfiguration = null)
{
AuthContextConfiguration = AuthContextConfiguration ?? new AuthContextConfiguration(context);
}
private void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}

}

public void SignIn(string userName, bool createPersistentCookie)
{
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}

public void SignIn(string userName, bool createPersistentCookie, ICookieUserData userData)
{
this.SetAuthCookie<ICookieUserData>(userName, true, userData);
HttpContext.Current.Cache.Insert(userName, userData);
}


public int SetAuthCookie<T>( string name, bool rememberMe, T userData)
{
/// In order to pickup the settings from config, we create a default cookie and use its values to create a
/// new one.

if (string.IsNullOrEmpty(((ICookieUserData)userData).Name)) ((ICookieUserData)userData).Name = name;
var cookie = FormsAuthentication.GetAuthCookie(name, rememberMe);
var ticket = FormsAuthentication.Decrypt(cookie.Value);

var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration,
ticket.IsPersistent, new JavaScriptSerializer().Serialize(userData), ticket.CookiePath);
var encTicket = FormsAuthentication.Encrypt(newTicket);

/// Use existing cookie. Could create new one but would have to copy settings over...
cookie.Value = encTicket;

HttpContext.Current.Response.Cookies.Add(cookie);

return encTicket.Length;
}


public void SignOut()
{
FormsAuthentication.SignOut();
}

public bool IsAuthorized()
{
return HttpContext.Current.User != null &&
HttpContext.Current.User.Identity != null &&
HttpContext.Current.User.Identity.IsAuthenticated;

}

public void SetUserOnApplication_AuthenticateRequest<T>(HttpContext context)
{
PrincipalUser principal = null;
ICookieUserData userData = null;
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = context.Request.Cookies[cookieName];


if (null == authCookie)
{
// There is no authentication cookie.
return;
}

var nameIdentity = HttpContext.Current.User.Identity.Name;
if(string.IsNullOrEmpty(nameIdentity)) {
return;
}

if(HttpContext.Current.Cache[nameIdentity] ==null) {
FormsAuthenticationTicket authTicket = null;
try {
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex) {
// Log exception details (omitted for simplicity)
return;
}

if (null == authTicket) {
// Cookie failed to decrypt.
return;
}

userData = (ICookieUserData)new JavaScriptSerializer().Deserialize<T>(authTicket.UserData);

// When the ticket was created, the UserData property was assigned a
// pipe delimited string of role names.
string[] roles = authTicket.UserData.Split('|');

// Create an Identity object
//FormsIdentity id = new FormsIdentity(authTicket);


// This principal will flow throughout the request.
//PrincipalUser principal = new PrincipalUser(id, roles);

} else {
userData = (ICookieUserData)HttpContext.Current.Cache[nameIdentity];
}
principal = new PrincipalUser(userData);




// Attach the new principal object to the current HttpContext object
context.User = principal;
}

public void CheckAuthorization()
{
if (!this.IsAuthorized()) throw new Exception("Access not allowed");
}

public void CheckAuthorizationForUrl(string url)
{
AuthContextConfiguration.CheckAuthorizationForUrl(url);
if (AuthContextConfiguration.CheckRequiredAuth() && !this.IsAuthorized()) throw new Exception("Access not allowed");
}
}

public class PrincipalUser : IPrincipal
{
private ICookieUserData _userData;
private GenericIdentity _identity;
public PrincipalUser(ICookieUserData userData)
{
_identity = new GenericIdentity(userData.Name);
_userData = userData;
}

public IIdentity Identity
{
get
{
return _identity;
}
}

public ICookieUserData UserData
{
get
{
return _userData;
}
}

public bool IsInRole(string role)
{
return _userData.Role.Contains(role);
}


}


public interface ICookieUserData
{
string Name { get; set; }
string Role { get; set; }
}


}

现在的问题是,当我从 [TestMethod] 调试并进入调试方法 (F10) 并在 HomeController.cs 的方法中放置断点时,我看到了这个 System.Web.HttpContext.Current 每次都是空的!有什么问题?我使用最小起订量。

最佳答案

System.Web.HttpContext.Current 由在单元测试期间不存在/不活动的 IIS 填充。因此 null。出于这个原因,不要将您的代码与 HttpContext 紧密耦合。而是将其封装在可以在隔离测试时模拟的抽象背后。

撇开糟糕的设计不谈,对于您的特定设计,您正试图访问 Controller 外部的静态依赖项。如果像当前测试中演示的那样伪造 Controller 的上下文,则访问 Controller 的上下文而不是调用静态上下文。

//... code removed for brevity

var _authProvider = new AuthenticationProvider(this.HttpContext);

//... code removed for brevity

除此之外, Controller 的设计应该重构为明确依赖于抽象而不是具体化。

例如,这里是提供者的抽象

public interface IAuthenticationProvider : IFormsAuthentication {
void CheckAuthorizationForUrl(string url);

//...other members
}

public class AuthenticationProvider : IAuthenticationProvider {

//...

}

Controller 应该通过构造函数注入(inject)明确地依赖于此

public class HomeController : Controller {
private readonly IAuthenticationProvider authProvider;

public HomeController(IAuthenticationProvider authProvider) {
this.authProvider = authProvider;
}

public ActionResult Index() {
ViewBag.Title = "Home Page";

var guidAccount = "xxxxxxxx-xxxx-xxxx-xxxx-422632e0bd95";

var userData = new CookieUserData(guidAccount) { GuidAccount = guidAccount };

authProvider.CheckAuthorizationForUrl("http://pippo");

return View();
}
}

如果使用依赖注入(inject),IAuthenticationProvider 实现应该配置为在运行时使用框架的 DependencyResolver 注入(inject) Controller ,但现在可以在测试 Controller 时替换隔离,以免与框架实现问题耦合。

[TestClass]
public class HomeControllerTest {
[TestMethod]
public void Index(){
// Disposizione
var authMock = new Mock<IAuthenticationProvider>();
var controller = new HomeController(authMock.Object);

// Azione
ViewResult result = controller.Index() as ViewResult;

// Asserzione
Assert.IsNotNull(result);
Assert.AreEqual("Home Page", result.ViewBag.Title);
}
}

关于c# - 为什么 HttpContext 为空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49687708/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com