2009-01-10 23 views
22

Tôi đã hỏi một câu hỏi liên quan nhưng đã làm hỏng tiêu đề và không ai hiểu được nó. Vì bây giờ tôi có thể đặt câu hỏi chính xác hơn, tôi đã quyết định cải cách câu hỏi này thành một câu hỏi mới và đóng câu hỏi cũ. Xin lỗi vì chuyện đó.Tại sao người dùng (như trong User.Identity.Name) null trong bộ điều khiển cơ sở trừu tượng của tôi?

Vì vậy, những gì tôi muốn làm là chuyển dữ liệu (biệt hiệu của người dùng tùy chỉnh của tôi như được lưu trữ trong db) vào LoginUserControl. Đăng nhập này được trả lại từ trang chủ thông qua Html.RenderPartial(), vì vậy những gì tôi thực sự cần làm là đảm bảo rằng, nói ViewData ["UserNickname"] có mặt trên mọi cuộc gọi. Nhưng tôi không muốn điền vào ViewData ["UserNickname"] trong mỗi và mọi hành động của mọi bộ điều khiển, vì vậy tôi quyết định sử dụng this approach và tạo bộ điều khiển cơ sở trừu tượng sẽ thực hiện công việc cho tôi, như vậy:

public abstract class ApplicationController : Controller 
    { 
     private IUserRepository _repUser; 

     public ApplicationController() 
     { 
      _repUser = RepositoryFactory.getUserRepository(); 
      var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem! 
      ViewData["LoggedInUser"] = loggedInUser; 
     } 
    } 

Bằng cách này, bất kỳ Bộ điều khiển phát sinh nào của tôi, thông tin người dùng sẽ có mặt.

Cho đến nay, rất tốt. Bây giờ cho vấn đề:

Tôi không thể gọi User.Identity.Name vì User đã bị vô hiệu. Đây không phải là trường hợp trong tất cả các bộ điều khiển của tôi, vì vậy điều này là cụ thể cho bộ điều khiển cơ sở trừu tượng.

Tôi đang đặt User.Identity.Name thông qua FormsAuthentication tại một vị trí khác trong mã, nhưng tôi nghĩ rằng điều này không thể là vấn đề - afaik User.Identity.Name có thể là null, nhưng không phải là chính Người dùng.

Dường như với tôi như HttpContext không có sẵn (vì cũng null ;-) và tôi thiếu một điểm đơn giản nhưng quan trọng ở đây. Bất cứ ai có thể cho tôi một số gợi ý? Tôi thực sự sẽ đánh giá cao nó.

Trả lời

12

Dự đoán của tôi là bộ khởi tạo cơ sở của Bộ điều khiển không được điền vào Người dùng, nhưng nó chỉ được biết sau này khi ControllerContext được đặt cho Bộ điều khiển. Bạn nên kiểm tra điều này trong tài liệu về vòng đời của một ứng dụng MVC, (có thể là here, mặc dù nó có thể hơi lỗi thời vì nó dành cho phiên bản xem trước), hoặc chỉ kiểm tra mã nguồn của MVC.

từ mã mà tôi có trong MVC (cũng là một phiên bản xem trước, nhưng đó phải là tốt): (Trong điều khiển)

public IPrincipal User { 
      get { 
       return HttpContext == null ? null : HttpContext.User; 
      } 
     } 

...

public HttpContextBase HttpContext { 
     get { 
      return ControllerContext == null ? null : ControllerContext.HttpContext; 
     } 
    } 

I don' t thấy vi thực hiện một hàm tạo mặc định trong mã. Điều đó sẽ chứng minh rằng ControllerContext là null tại thời điểm xây dựng.

Vì vậy, bạn nên thực thi mã của mình ở một nơi khác.

+7

Lạ, vì 'Người dùng' là null nhưng' System.Web.HttpContext.Current.User' thì không. MVC 1.0 –

4

Bạn có thể grab này sử dụng một cái gì đó như:

HttpContext currentContext = HttpContext.Current; 
string userName = currentContext.User.Identity.Name; 

Hoặc là HttpContext luôn có sản phẩm nào ??

Bạn có thể đặt httpContext thông qua hàm tạo của lớp trừu tượng không? và sử dụng nó theo cách này?

4

Cảm ơn Raimond. Tôi đã quá mệt mỏi để thấy rõ ràng. @Keeney: Có ngữ cảnh luôn là rỗng. Raimond chỉ ra tại sao.Dù sao, tôi cũng không thấy lý do tại sao :-)

Giải pháp làm việc hiện tại của tôi (mặc dù không phải những gì tôi muốn) là thuộc tính mà tôi sử dụng để trang trí tất cả các hành động điều khiển của mình. Đây là việc thực hiện:

public class MasterPageDataAttribute : ActionFilterAttribute 
    { 
     public override void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      base.OnActionExecuting(filterContext); 
      IUserRepository _repUser = RepositoryFactory.getUserRepository(); 
      IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User; 
      User loggedInUser = null; 

      if (siteUser == null || siteUser.Identity.Name == null) 
      { 
       //do nothing 
      } 
      else 
      { 
       loggedInUser = _repUser.findUserById(siteUser.Identity.Name); 
      } 
      filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" }; 
     } 
    } 

tôi sẽ nhìn vào cách để có được mã thực thi trong một cách mà theo nguyên tắc DRY, vì sử dụng các thuộc tính cho điều đó chắc chắn có nghĩa là lặp lại chính mình. Có lẽ một số loại máy bay đánh chặn (interesting idea) hoặc móc có thể hữu ích.

Chúc mừng cho điều đó.

+1

Tôi khuyên bạn nên ghi đè phương thức Initialize của lớp Controller tùy chỉnh của bạn và di chuyển mã của bạn từ constructor đến đó. – jcmcbeth

0

Tôi đang thực hiện việc này trong quá trình triển khai cơ sở dữ liệu và nó hoạt động như mong đợi.

public abstract class BaseController : Controller 
{ 
    public bool LoggedOn 
    { 
     get { return User.Identity.IsAuthenticated; } 
    } 
} 

luôn này trả về đúng hay sai đối với tôi rất User != null

+0

Điều này là do đối tượng Người dùng đó được điền vào trong lúc Thuộc tính LoggedOn được gọi. – jcmcbeth

21

Câu trả lời cho vấn đề này là thực sự khá đơn giản. Tôi không thể thực thi mã từ bên trong hàm tạo vì các lý do được chỉ ra bởi Raimond, nhưng tôi có thể thực hiện nó bên ngoài hàm tạo. Vì vậy, những gì tôi đã làm là ghi đè lên lớpActionExecuting() trong lớp điều khiển cơ sở (tôi đã tạo thuộc tính tùy chỉnh cho nó, nhưng chỉ ghi đè phương thức cũng sẽ hoạt động) và sau đó thực hiện tra cứu người dùng của tôi từ đó.

Bây giờ, nó hoạt động như mong đợi và tôi không có mã lặp lại.

+0

Cảm ơn bạn đã đăng cách bạn giải quyết rằng – JeremyWeir

+0

Niềm vui của tôi :-) – Masterfu

0

để Masterfu: Tôi đã làm điều gì đó tương tự với sự giúp đỡ của bạn, mong muốn có thể giúp khách truy cập thứ hai. Trong trường hợp của tôi, tôi cần phải tạo reposiotry của bộ điều khiển cho người dùng khác nhau, nhưng trong các nhà xây dựng của bộ điều khiển, (chính) Người dùng chưa sẵn sàng. Vì vậy, tôi đã tạo ra một thuộc tính cho điều khiển:

[CreateRepositoryByUser] 
public class MFCController : Controller 
{ 
    protected MFCRepository _repository 
    { 
     get { return ViewData["repository"] as MFCRepository; } 
    } 
... 

các _repository, quả thật vậy, không phải là một biến riêng của bộ điều khiển, nhưng somethign tạo bởi thuộc tính:

public class CreateRepositoryByUser : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     CreateRepository(filterContext); 
    } 

    public static void CreateRepository(ActionExecutingContext filterContext) 
    { 
     if (filterContext.Controller.ViewData["repository"] == null) 
     { 
      filterContext.Controller.ViewData["repository"] = 
       MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User); 
     } 
    } 
} 

tôi đặt mã của việc tạo ra các kho lưu trữ trong một phương pháp riêng biệt, trong trường hợp các thuộc tính khác có thể muốn sử dụng (chính) Người dùng trước khi thuộc tính này được kích hoạt.

0

Gọi từ một hàm tạo quá sớm trong đường ống MVC.

Chuyển mã sang OnAuthorization, bạn sẽ nhận được người dùng được ủy quyền trong tham số. Đã làm cho tôi!

Từ ví dụ của bạn tôi sẽ làm một cái gì đó như thế này:

public abstract class ApplicationController : Controller { 
    private IUserRepository _repUser; 

    protected override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     _repUser = RepositoryFactory.getUserRepository(); 
     var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem! 
     ViewData["LoggedInUser"] = loggedInUser; 
    } 


} 
11

Thuộc tính người dùng không được giao cho đến sau khi điều khiển đã được khởi tạo, nhưng bạn có thể tiếp cận đầu từ constructor của bạn với:

System.Web.HttpContext.Current.User 
Các vấn đề liên quan