MVC - Chia sẻ thông tin theo ngữ cảnh giữa các khung nhìn


8

Xin thứ lỗi cho bài viết dài. Có một câu hỏi, chỉ cần chịu đựng với tôi.

Một bối cảnh nhỏ

Chúng tôi có một trang web được yêu cầu thích nghi đáng kể dựa trên nhiều cài đặt người dùng, nhóm người dùng thuộc về, nơi họ đến và những thứ khác. Chúng tôi thường bao gồm các bit có liên quan trên mô hình cho trang, vì vậy nếu trang có bảng sẽ hiển thị nếu người dùng trên một độ tuổi nhất định, thì trên mô hình chúng tôi sẽ làm một cái gì đó như:

//model
public PageModel
{
    public bool ShowTable {get;set;}
}

//controller
public PageController
{
    public ActionResult ShowPage()
    {
        var model = new PageModel() {
            ShowTable = User.Age > 21
        };
        return View(model);
    }
}

//view
@if(Model.ShowTable)
{ 
    <table>Some Html here</table>
}

Điều này nhanh chóng trở nên rất phức tạp để biết những gì chúng ta nên hiển thị cho người dùng nào. Để thử và giải quyết vấn đề này, chúng tôi tập trung tất cả logic về thời điểm một thứ cụ thể sẽ được hiển thị hoặc ẩn đi. Chúng tôi đã gọi lớp này UserConfigurationvà nó (hầu hết) chỉ chứa một loạt các hàm trả về booleans chỉ ra những gì sẽ được hiển thị. Điều này cho phép chúng tôi thiết lập một loạt Thông số kỹ thuật và Thử nghiệm về những gì người dùng sẽ được hiển thị. Điều này UserConfigratuionsau đó được đưa vào một lớp cơ sở, mà tất cả các mô hình trang được yêu cầu kế thừa từ đó, vì vậy những gì chúng ta hiện đang có là như thế này:

//UserConfiguration 
public UserConfiguration
{
    private readonly User _user;

    public UserConfiguration(User user) {
        _user = user
    }

    public bool ShowTable() {
        return _user.Age > 21;
    }
}

//model base
public ModelBase
{
    public UserConfiguration {get;set;}
}

//model
public PageModel : ModelBase
{
    // whatever data is needed for the page
}

//controller
public PageController
{
    public ActionResult ShowPage()
    {
        var userConfiguration = new UserConfiguration(User);
        var model = new PageModel {
            UserConfiguration = userConfiguration
        };
        return View(model);
    }
}

//view
@if(Model.UserConfiguration.ShowTable())
{ 
    <table>Some Html here</table>
}

Điều này đã giúp ích, chủ yếu là vì nó cho phép chúng tôi tạo ra một loạt các thử nghiệm về những gì người dùng nên và không nên xem, v.v. Tuy nhiên, đó không phải là một giải pháp rất sạch sẽ, phải kết hợp lớp bổ sung này và đưa nó vào mô hình. Nó cũng có các phân nhánh để hiển thị Chế độ xem một phần. Nếu mô hình có một thuộc tính IEnumerable<Foo> Foostrên nó, mà chúng ta muốn kết xuất một phần, nhưng một phần đó cũng phụ thuộc vào cấu hình người dùng, chúng ta có một vấn đề. Bạn không thể chuyển các foos cho Partial như mô hình, bởi vì sau đó một phần không có quyền truy cập vào UserConfiguration. Vì vậy, những gì sẽ là cách tốt nhất để truy cập thông tin này. Theo cách tôi thấy, trong ngữ cảnh của asp.net MVC, có 4 cách khả dụng:

1) Có một mô hình mới cho một phần, ví dụ

// parent view
@{
    var foosModel = new foosModel {
        Foos = Model.Foos,
        UserConfiguration = Model.UserConfiguration
    }
}

@Html.RenderPartial("FooList", foosModel)

// child partial view
@if(Model.UserConfiguration.ShowTable) {
    foreach(var foo in Model.Foos) {
        //Some HTML
    }
}

Đây có lẽ là giải pháp "thuần túy nhất", tuân thủ tốt nhất các nguyên tắc của MVC, nhưng liên quan đến rất nhiều mô hình (được cho là không cần thiết), gây ra sự phình to của dự án.

2) Hiển thị Cấu hình người dùng thông qua ViewData. ví dụ :

// parent view
@Html.RenderPartial("FooList", Model.Foos, new ViewDataDictionary { { "UserConfiguration", Model.UserConfiguration } })

// child partial view
@{ 
    var userConfig = (UserConfiguration)ViewData["UserConfiguration"];
}
@if(userConfig.ShowTable) {
    foreach(var foo in Model) {
        //Some HTML
    }
}

Tôi không thực sự thích điều này bởi vì nó không phải là loại an toàn và dựa vào chuỗi ma thuật để lấy nó từ ViewData.

3) Đặt cấu hình người dùng trong ViewBag. Vấn đề tương tự như trên thực sự

4) Sửa đổi mô hình trang và hiển thị Cấu hình người dùng thông qua một thuộc tính của chính trang đó, theo http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view .aspx /

Tôi cảm thấy vì UserConfiguration là thông tin theo ngữ cảnh xung quanh, nên có ý nghĩa để hiển thị nó thông qua lớp như trong tùy chọn 4 ở trên. Có thường được chấp nhận thực hành tốt nhất trong MVC để hiển thị loại dữ liệu này? Có ai đã thử bất cứ điều gì như tùy chọn 4 trong quá khứ và có bất kỳ 'gotcha' nào không

tl; dr: Cách tốt nhất để hiển thị thông tin theo ngữ cảnh cho các chế độ xem trên trang web của bạn, trong MVC nói chung hoặc asp.net MVC nói riêng là gì?

Câu trả lời:


2

Bạn nên đi với # 5: Không có gì ở trên.

Tôi đã bắt đầu tạo các phương thức mở rộng cho IPrincipalgiao diện, giúp tôi khai báo mạnh mẽ về những gì người dùng hiện tại có thể làm. Bạn thậm chí có thể tạo một UserConfigurationDTO mà bạn nhét vào Phiên để sử dụng bởi các phương thức mở rộng này.

Đầu tiên, các phương thức mở rộng:

namespace YourApplication.Helpers
{
    public static class UserConfigurationExtensions
    {
        private HttpContext CurrentContext
        {
            get
            {
                return System.Web.HttpContext.Current;
            }
        }

        private static UserConfiguration Config
        {
            get
            {
                if (CurrentContext == null)
                    return null;

                return CurrentContext.Session["UserConfiguration"] as UserConfiguration;
            }
        }

        public static bool CanViewTable(this IPrincipal user)
        {
            return Config.ShowTable;
        }
    }
}

Bây giờ khi người dùng đã đăng nhập thành công, hãy tạo cá thể UserConfigurationvà bỏ nó vào Session:

public class AccountController : Controller
{
    [HttpPost]
    public ActionResult Login(LoginFormModel model)
    {
        if (ModelState.IsValid)
        {
            // Log in
            Session["UserConfiguration"] = new UserConfiguration(...);
        }

        return RedirectToAction("Index", "Home");
    }
}

Tiếp theo, thêm không gian tên trong đó các phương thức mở rộng tồn tại vào các không gian tên mặc định của bạn trong các mẫu Dao cạo.

Ứng dụng / Lượt xem / Web.config của bạn

<?xml version="1.0"?>

<configuration>
  <!-- ... -->

  <system.web.webPages.razor>
    <namespaces>
      <add namespace="YourApplication.Helpers"/>
    </namespaces>
  </system.web.webPages.razor>

  <!-- ... -->
</configuration>

Bây giờ hãy đóng và mở lại giải pháp Visual Studio. Sau đó, các mẫu Dao cạo của bạn có sẵn các phương thức mới:

@if (User.CanViewTable())
{
    foreach(var foo in Model)
    {
        //Some HTML
    }
}

0

Tôi sẽ đi với tùy chọn đầu tiên của bạn, thực hiện các sửa đổi cần thiết cho các lớp mô hình của bạn. Có vẻ như tùy chọn 4 của bạn, sửa đổi mô hình trang, sẽ giao dịch các tham chiếu Mô hình cho các tham chiếu của người trợ giúp trong chế độ xem dao cạo của bạn. Tùy chọn 1 có vẻ dễ bảo trì hơn tùy chọn 4 vì dường như sẽ cần ít mã hơn và vì nhiều nhà phát triển MVC sẽ hiểu nó hơn.


0

Ý kiến ​​của tôi là, dữ liệu theo ngữ cảnh với ViewBag / ViewData được cấu hình bởi dịch vụ dữ liệu theo ngữ cảnh. Tôi cảm thấy khó chịu vì không có hoặc rất kém tính linh hoạt khi có "BaseContoder", thiết lập tất cả mọi thứ từ "GodModel" vì mọi chế độ xem đều cần có trừ khi tôi cần thêm một số chế độ xem mỏng mới mà tôi không cần tất cả những thứ đó. Tất nhiên, "GodModel" cũng là một lớp cơ sở cho các mô hình trong các khung nhìn.

Thật khó để nói trước nếu một cái gì đó thực sự cần thiết bởi các quan điểm "tất cả" và làm cho nhiều thứ bắt buộc khiến tôi khó khăn hơn nhiều so với việc tạo ra các công cụ tùy chọn và thỉnh thoảng tôi quên thiết lập vì nó rất năng động .

Tất nhiên tất cả các chế độ xem cụ thể và thực sự bắt buộc phải được mô hình hóa và được gõ mạnh mẽ và có xác nhận. Nhưng những thứ chung chung có thể làm giảm hiệu suất vì ai đó nghĩ rằng "mọi thứ phải được gõ mạnh" là không tốt.


0

có vẻ như MOST của thông tin bạn cần kiểm tra là lấy người dùng làm trung tâm và không dựa trên hành động. tại sao không lưu trữ UserConfiguration của bạn trong phiên? một cách tiếp cận khác, tùy thuộc vào cách bạn thực hiện xác thực / quản lý người dùng, là giữ tất cả thông tin bạn cần trong ClaimsPrincipal (mẫu bên dưới) ...

    private ClaimsPrincipal CurrentClaimsPrincipal
    {
        get { return System.Security.Claims.ClaimsPrincipal.Current; }
    }

    public string Firstname
    {
        get { return (null != CurrentClaimsPrincipal) ? CurrentClaimsPrincipal.FindFirst(Helpers.Constants.GIVEN_NAME_KEY)?.Value : string.Empty; }
    }

    public string Lastname
    {
        get { return (null != CurrentClaimsPrincipal) ? CurrentClaimsPrincipal.FindFirst(Helpers.Constants.FAMILY_NAME_KEY)?.Value : string.Empty; }
    }

    public string AccessLevel
    {
        get { return (null != CurrentClaimsPrincipal) ? CurrentClaimsPrincipal.FindFirst(Helpers.Constants.ACCESS_LEVEL_KEY)?.Value : string.Empty; }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.