Mô-đun Javascript, MVC dựa trên máy chủ và thực tế kinh doanh


32

Tôi hiểu đây là một câu hỏi rất rộng, nhưng tôi đã làm việc với nhiều khía cạnh khác nhau của vấn đề này và đang đấu tranh để mang tất cả các khái niệm và công nghệ lại với nhau.

Tôi muốn xác định rằng câu trả lời nên bao gồm các công nghệ sau:

  • C #
  • MVC 3 w / Dao cạo
  • Javascript với / jQuery

Bất cứ điều gì ở trên và ngoài những thứ đó (như Backbone.js , Entity Framework , v.v.) đều được chào đón dưới dạng các đề xuất nếu chúng giúp trả lời câu hỏi đó là:

Sử dụng các công nghệ được liệt kê ở trên, một chiến lược tối ưu để tổ chức mã và logic trong khi duy trì khả năng mở rộng và khả năng tạo giao diện người dùng phong phú, nhanh chóng, sạch sẽ là gì?

Tốt nhất nên tập trung vào một giải pháp đang được triển khai trong môi trường kinh doanh / doanh nghiệp. Trên lưu ý đó, danh sách công nghệ ở trên sẽ không bị thay đổi, vì vậy vui lòng không cung cấp giải pháp với "bạn nên sử dụng xxx thay vì yyy mà bạn hiện đang sử dụng".

Lý lịch

Tôi làm việc với jQuery hàng ngày, đã áp dụng MVC của ASP.NET và đã làm việc với C # trong một thời gian dài. Vì vậy, bạn có thể trình bày các giải pháp giả định kiến ​​thức từ trung cấp đến nâng cao về các công nghệ đó.

Tôi sẽ sắp xếp câu hỏi thành các phần nhỏ hơn để trả lời đơn giản hơn:

1. Cấu trúc dự án

Cho rằng tôi đang làm việc với ASP.NET MVC (trong Visual Studio 2010 ) Tôi muốn một giải pháp cấu trúc thư mục cung cấp sự chấp nhận bố cục chính của loại ứng dụng này. Một cái gì đó giống như Brunch tôi cho rằng, nhưng với một chi tiết nhỏ hơn về mỗi thư mục sẽ chứa gì và cách thức hoạt động với các khu vực khác của ứng dụng.

2. Truy cập dữ liệu

Tôi muốn mô đun hóa truy cập dữ liệu của mình nhiều nhất có thể, với cấu trúc kiểu API. Bạn có thể giả định nhiều đối tượng POCO ( User, UserGroup, Customer, OrderHeader, OrderDetails, vv), nhưng cũng sẽ có một số báo cáo phức tạp đòi hỏi dữ liệu SQL thâm canh và UI vẽ cẩn thận. EF + LINQ là tuyệt vời cho cái trước nhưng không nhiều cho cái sau. Tôi không thể tìm thấy thứ gì đó có vẻ phù hợp với cả hai kịch bản mà không quá phức tạp hoặc quá đơn giản.

3. Tổ chức mã phía khách hàng và kết xuất giao diện người dùng

Giống như hầu hết các nhà phát triển lần đầu tiên chọn jQuery, tôi rơi vào cái bẫy trộn mã bất cứ nơi nào cần đến nhưng nhanh chóng thấy nó chồng chất và trở nên xấu xí. Mặc dù tôi đã có những bước nhảy vọt kể từ đó, tôi vẫn đấu tranh với việc mô đun hóa mã của mình và làm việc với các phần khác nhau của giao diện người dùng mà không cần lặp lại mã.

Ví dụ, một đoạn mã điển hình tôi có thể viết sẽ giống như thế này, tôi đã nhận xét nội dung làm phiền tôi ( lưu ý rằng tôi đã thay đổi sử dụng các cuộc gọi AJAX bị trì hoãn và tách các yêu cầu dữ liệu thực tế khỏi thao tác DOM ):

$('#doSomethingDangerous').click(function () {
    // maybe confirm something first
    if (confirm('Are you sure you want to do this?')) {   

        // show a spinner?  something global would be preferred so I don't have to repeat this on every page 
        $('#loading').show();  

        // maybe the page should notify the user of what's going on in addition to the dialog?
        $('#results').show().html('<h2>Please wait, this may take a while...</h2>');  

        $.ajax({
            url: 'blah/DoDangerousThing',
            success: function (data) {                     
                // The results will be loaded to the DOM obviously, is there a better way to pull this type of specific code out of the data access calls?
                $('#results').empty();
                $('#results').append('<b>' + data.length + '</b> users were affected by this dangerous activity');
                $('#results').append('<ul>');

                // I've recently started to use jQuery templates for this sort of logic, is that the way to go?
                $(data).each(function (i, user) {
                    $('#results').append('<li>' + user.Username + '</li>');
                });                    
                $('#results').append('</ul>');

                // Need to hide the spinner, again would prefer to have this done elsewhere
                $('#loading').hide();
            }
        });
    }
});

Câu hỏi chung

  • MVC khách hàng so với máy chủ MVC? Dự án của tôi đã là một cấu trúc MVC phía máy chủ, vậy vẫn còn nhu cầu về MVC khách hàng như Backbone.js cung cấp?
  • Các tệp Javascript có nên được tạo cho từng đối tượng (như một OrderHeader.js) và sau đó được thu nhỏ / hợp nhất trong quá trình xây dựng không? Hoặc chỉ nên có một Order.jscái có logic cho OrderHeader, OrderDetails, Reportsvv?
  • Làm thế nào các truy vấn phức tạp nên được xử lý? Ngay bây giờ, lý thuyết hàng đầu của tôi là /Reports/Orders-By-Date/hoặc một cái gì đó dọc theo các dòng đó và tôi sử dụng truy vấn SQL tùy chỉnh để hiển thị một bộ dữ liệu tùy chỉnh (hoặc ViewModel) cho Chế độ xem dao động. Nhưng những gì về phân trang, phân loại, vv? Điều này tốt hơn để được thực hiện phía khách hàng hoặc máy chủ? (giả sử tập dữ liệu lớn hơn - truy vấn SQL 2 đến 3 giây)
  • Tôi đã đọc qua Dự án Silk của Microsoft . Đây có phải là một cách tốt để đi? Làm thế nào để nó so sánh với Backbone.js hoặc những người khác?
  • Tôi đã rất quen với một kiến ​​trúc N tầng, những khái niệm này có phần nào ném nó ra ngoài cửa sổ không? Có vẻ như MVC giống như một loạt các phần N tầng nhỏ bên trong những gì sẽ là tầng trước hoặc tầng trên cùng trong quá khứ.

Một lần nữa, câu trả lời của bạn càng cụ thể thì càng tốt. Tôi đã đọc rất nhiều tài liệu và ví dụ cấp cao , tôi đang cố gắng hiểu rõ hơn về việc dịch nó thành các ví dụ trong thế giới thực .


2
Bạn đặt rất nhiều nỗ lực vào câu hỏi này, nhưng nó dường như không phải là một câu hỏi Stackoverflow đối với tôi. Có lẽ các lập trình viên stackexchange sẽ phù hợp hơn.
Pointy

3
Tôi không đồng ý rằng đó là một chủ đề thú vị, nhưng Stackoverflow được cho là về các câu hỏi khách quan . Một cái gì đó giống như câu hỏi này về cơ bản là đứa trẻ áp phích cho các câu hỏi sẽ "có khả năng thu hút ý kiến, tranh luận, tranh luận, bỏ phiếu hoặc thảo luận mở rộng."
Mũi nhọn

8
Có một trại gồm những người lập kế hoạch cho quy mô lớn nhất mọi lúc trong khi tôi lặng lẽ lấy đi công việc của họ vì họ mất quá nhiều kế hoạch cho một điều không bao giờ xảy ra.
Jason Sebring

1
Tôi đồng ý với @Pointy rằng điều này thuộc về nhóm Lập trình viên. Câu hỏi của bạn rất thú vị, và tôi sẽ trả lời vì tôi luôn tìm kiếm lời khuyên. Nhưng nó không phải là một câu hỏi khách quan, và sẽ chỉ kết thúc trong các cuộc tranh luận ưu đãi. Như mọi khi, hãy làm những gì tốt nhất cho tình huống của bạn ... không ai trong chúng tôi biết bất cứ điều gì về cấu trúc mạng, số lượng khách hàng hoặc chỉ số lưu lượng truy cập hoặc quy trình xây dựng ... vì vậy câu hỏi là CÁCH quá mơ hồ ... tất cả những gì tôi biết là tránh tơ tằm. ;)
one.beat.consumer

1
Câu hỏi này phù hợp với định nghĩa "quá rộng" và do đó "không phải là một câu hỏi thực sự". Nếu có bất cứ điều gì, các câu hỏi riêng lẻ nên được hỏi dưới dạng câu hỏi riêng lẻ với một số nền tảng nhỏ (quá nhiều và mọi người sẽ đánh dấu nó "không phải là một câu hỏi thực sự"). Tuy nhiên, hãy cẩn thận, một số câu hỏi cá nhân bạn đang hỏi có thể được gắn cờ là "không mang tính xây dựng", vì vậy tôi sẽ cẩn thận về cách bạn hỏi những câu hỏi đó.
casperOne

Câu trả lời:


10

TerryR bạn của tôi, bạn và tôi nên có một thức uống. Chúng tôi có một số vấn đề tương tự.

1. Cấu trúc dự án: Tôi đồng ý với Eduardo rằng cấu trúc thư mục trong ứng dụng MVC để lại thứ gì đó mong muốn. Bạn có các thư mục Bộ điều khiển, Mô hình và Chế độ xem chuẩn. Nhưng sau đó, thư mục Lượt xem được chia thành một thư mục khác nhau cho mỗi Trình điều khiển, cộng với thư mục Dùng chung. Và mỗi Lượt xem / Tên điều khiển hoặc Lượt xem / Chia sẻ có thể được chia thành EditorTemsheet và DisplayTemsheet. Nhưng nó cho phép bạn quyết định cách tổ chức thư mục Mô hình của bạn (bạn có thể thực hiện có hoặc không có thư mục con & khai báo không gian tên bổ sung).

Chúa cấm bạn đang sử dụng các Khu vực trùng lặp cấu trúc thư mục Bộ điều khiển, Mô hình và Chế độ xem cho từng khu vực.

/Areas
    /Area1Name
        /Controllers
            FirstController.cs
            SecondController.cs
            ThirdController.cs
        /Models
            (can organize all in here or in separate folders / namespaces)
        /Views
            /First
                /DisplayTemplates
                    WidgetAbc.cshtml <-- to be used by views in Views/First
                /EditorTemplates
                    WidgetAbc.cshtml <-- to be used by views in Views/First
                PartialViewAbc.cshtml <-- to be used by FirstController
            /Second
                PartialViewDef.cshtml <-- to be used by SecondController
            /Third
                PartialViewMno.cshtml <-- to be used by ThirdController
            /Shared
                /DisplayTemplates
                    WidgetXyz.cshtml <-- to be used by any view in Area1
                /EditorTemplates
                    WidgetXyz.cshtml <-- to be used by any view in Area1
                PartialViewXyz.cshtml <-- to be used anywhere in Area1
            _ViewStart.cshtml <-- area needs its own _ViewStart.cshtml
            Web.config <-- put custom HTML Helper namespaces in here
        Area1NameRegistration.cs <-- define routes for area1 here
    /Area2Name
        /Controllers
        /Models
        /Views
        Area2NameRegistration.cs <-- define routes for area2 here

/Controllers
    AccountController.cs
    HomeController.cs
/Models
/Views
    /Account
        /DisplayTemplates
            WidgetGhi.cshtml <-- to be used views in Views/Account
        /EditorTemplates
            WidgetGhi.cshtml <-- to be used views in Views/Account
        PartialViewGhi.cshtml <-- to be used by AccountController
    /Home
        (same pattern as Account, views & templates are controller-specific)
    /Shared
        /DisplayTemplates 
            EmailAddress.cshtml <-- to be used by any view in any area
            Time.cshtml <-- to be used by any view in any area
            Url.cshtml <-- to be used by any view in any area
        /EditorTemplates
            EmailAddress.cshtml <-- to be used by any view in any area
            Time.cshtml <-- to be used by any view in any area
            Url.cshtml <-- to be used by any view in any area
        _Layout.cshtml <-- master layout page with sections
        Error.cshtml <-- custom page to show if unhandled exception occurs
    _ViewStart.cshtml <-- won't be used automatically in an area
    Web.config <-- put custom HTML Helper namespaces in here

Điều này có nghĩa là nếu bạn đang làm việc với một cái gì đó như WidgetContoder, bạn phải tìm trong các thư mục khác để tìm WidgetViewModels, WidgetViews, WidgetEditorTemsheet, WidgetDisplayTemsheet, v.v. những quy ước MVC này. Theo như đặt một mô hình, bộ điều khiển và chế độ xem trong cùng một thư mục nhưng với các không gian tên khác nhau, tôi tránh điều này vì tôi sử dụng ReSharper. Nó sẽ nguệch ngoạc gạch chân một không gian tên không khớp với thư mục nơi lớp được đặt. Tôi biết tôi có thể tắt tính năng R # này, nhưng nó giúp trong các phần khác của dự án.

Đối với các tệp không phải là lớp, MVC cung cấp cho bạn Nội dung và Tập lệnh. Chúng tôi cố gắng giữ tất cả các tệp tĩnh / không được biên dịch của chúng tôi ở những nơi này, một lần nữa, để tuân theo quy ước. Bất cứ khi nào chúng tôi kết hợp một thư viện js sử dụng các chủ đề (hình ảnh và hoặc css), các tệp chủ đề đều nằm ở đâu đó bên dưới / nội dung. Đối với tập lệnh, chúng tôi chỉ cần đặt tất cả chúng trực tiếp vào / script. Ban đầu, điều này là để nhận được intellisense từ VS, nhưng bây giờ chúng tôi nhận được intellisense từ R # bất kể vị trí trong / script, tôi cho rằng chúng ta có thể đi chệch khỏi đó và chia các tập lệnh theo thư mục để tổ chức tốt hơn. Bạn đang sử dụng ReSharper? Đó là IMO vàng nguyên chất.

Một miếng vàng nhỏ khác giúp ích rất nhiều cho việc tái cấu trúc là T4MVC. Sử dụng điều này, chúng ta không cần phải nhập các đường dẫn chuỗi cho tên khu vực, tên bộ điều khiển, tên hành động, thậm chí các tệp trong nội dung & tập lệnh. T4MVC mạnh mẽ gõ tất cả các chuỗi ma thuật cho bạn. Đây là một ví dụ nhỏ về cách cấu trúc dự án của bạn không quan trọng bằng nếu bạn đang sử dụng T4MVC:

// no more magic strings in route definitions
context.MapRoutes(null,
    new[] { string.Empty, "features", "features/{version}" },
    new
    {
        area = MVC.PreviewArea.Name,
        controller = MVC.PreviewArea.Features.Name,
        action = MVC.PreviewArea.Features.ActionNames.ForPreview,
        version = "december-2011-preview-1",
    },
    new { httpMethod = new HttpMethodConstraint("GET") }
);

@* T4MVC renders .min.js script versions when project is targeted for release *@
<link href="@Url.Content(Links.content.Site_css)?r=201112B" rel="stylesheet" />
<script src="@Url.Content(Links.scripts.jquery_1_7_1_js)" type="text/javascript">
</script>

@* render a route URL as if you were calling an action method directly *@
<a href="@Url.Action(MVC.MyAreaName.MyControllerName.MyActionName
    (Model.SomeId))">@Html.DisplayFor(m => m.SomeText)</a>

// call action redirects as if you were executing an action method
return RedirectToAction(MVC.Area.MyController.DoSomething(obj1.Prop, null));

2. Truy cập dữ liệu: Tôi không có kinh nghiệm với PetaPoco, nhưng tôi chắc chắn rằng nó đáng để kiểm tra. Đối với các báo cáo phức tạp của bạn, bạn đã xem xét các dịch vụ Báo cáo Máy chủ SQL chưa? Hoặc, bạn đang chạy trên một db khác nhau? Xin lỗi tôi không rõ chính xác những gì bạn đang yêu cầu. Chúng tôi sử dụng EF + LINQ, nhưng chúng tôi cũng đưa một số kiến ​​thức nhất định về cách tạo báo cáo trong các lớp miền. Vì vậy, chúng ta có kho lưu trữ cuộc gọi dịch vụ miền điều khiển, thay vì có kho lưu trữ cuộc gọi điều khiển trực tiếp. Đối với các báo cáo đặc biệt, chúng tôi sử dụng Dịch vụ báo cáo SQL, một lần nữa không hoàn hảo, nhưng người dùng của chúng tôi muốn có thể đưa dữ liệu vào Excel một cách dễ dàng và SSRS giúp chúng tôi dễ dàng.

3. Tổ chức mã phía khách hàng và kết xuất giao diện người dùng: Đây là nơi tôi nghĩ rằng tôi có thể cung cấp một số trợ giúp. Lấy một trang từ cuốn sách xác thực MVC không phô trương và AJAX không phô trương. Xem xét điều này:

<img id="loading_spinner" src="/path/to/img" style="display:none;" />
<h2 id="loading_results" style="display:none;">
    Please wait, this may take a while...
</h2>
<div id="results">
</div>
<input id="doSomethingDangerous" class="u-std-ajax" 
    type="button" value="I'm feeling lucky" 
    data-myapp-confirm="Are you sure you want to do this?"
    data-myapp-show="loading_spinner,loading_results" 
    data-myapp-href="blah/DoDangerousThing" />

Bỏ qua chức năng thành công ajax bây giờ (nhiều hơn về điều này sau). Bạn có thể thoát khỏi một tập lệnh cho một số hành động của mình:

$('.u-std-ajax').click(function () {
    // maybe confirm something first
    var clicked = this;
    var confirmMessage = $(clicked).data('myapp-confirm');
    if (confirmMessage && !confirm(confirmMessage )) { return; } 

    // show a spinner?  something global would be preferred so 
    // I dont have to repeat this on every page 
    // maybe the page should notify the user of what's going on 
    // in addition to the dialog?
    var show = $(clicked).data('myapp-show');
    if (show) {
        var i, showIds = show.split(',');
        for (i = 0; i < showIds.length; i++) {
            $('#' + showIds[i]).show();
        }
    }

    var url = $(clicked).data('myapp-href');
    if (url) {
        $.ajax({
            url: url,
            complete: function () {                     
                // Need to hide the spinner, again would prefer to 
                // have this done elsewhere
                if (show) {
                    for (i = 0; i < showIds.length; i++) {
                        $('#' + showIds[i]).hide();
                    }
                }
            }
        });
    }
});

Đoạn mã trên sẽ đảm nhận việc xác nhận, hiển thị spinner, hiển thị thông báo chờ và ẩn tin nhắn spinner / Wait sau khi cuộc gọi ajax hoàn tất. Bạn định cấu hình các hành vi bằng cách sử dụng các thuộc tính data- *, như các thư viện không phô trương.

Câu hỏi chung

- Máy khách MVC so với máy chủ MVC? Tôi đã không cố gắng hiệu chỉnh các hành động bạn đã thực hiện trong hàm thành công vì có vẻ như bộ điều khiển của bạn đang trả về JSON. Nếu bộ điều khiển của bạn đang trả về JSON, bạn có thể muốn xem KnockoutJS. Knockout JS phiên bản 2.0 đã được phát hành ngày hôm nay . Nó có thể cắm ngay vào JSON của bạn, để một nhấp chuột có thể quan sát có thể tự động liên kết dữ liệu với các mẫu javascript của bạn. Mặt khác, nếu bạn không phiền khi các phương thức hành động ajax của bạn trả về HTML thay vì JSON, chúng có thể trả về UL đã được xây dựng với các con LI của nó và bạn có thể thêm nó vào một phần tử bằng cách sử dụng data-myapp-answer = "các kết quả". Chức năng thành công của bạn sau đó sẽ trông như thế này:

success: function(html) {
    var responseId = $(clicked).data('myapp-response');
    if (responseId) {
        $('#' + responseId).empty().html(html);
    }
}

Để tổng hợp câu trả lời tốt nhất của tôi cho điều này, nếu bạn phải trả về JSON từ các phương thức hành động của mình, bạn đang bỏ qua Chế độ xem phía máy chủ, vì vậy đây thực sự không phải là máy chủ MVC - đó chỉ là MC. Nếu bạn trả lại PartialViewResult bằng html cho các cuộc gọi ajax, thì đây là máy chủ MVC. Vì vậy, nếu ứng dụng của bạn phải trả về dữ liệu JSON cho các cuộc gọi ajax, hãy sử dụng MVVM của máy khách như KnockoutJS.

Dù bằng cách nào, tôi không thích JS bạn đã đăng vì nó trộn bố cục của bạn (thẻ html) với hành vi (tải dữ liệu không đồng bộ). Chọn một trong hai máy chủ MVC với các khung nhìn html một phần hoặc MVVM của máy khách với dữ liệu chế độ xem JSON thuần sẽ giải quyết vấn đề này cho bạn, nhưng việc xây dựng DOM / HTML theo cách thủ công trong javascript vi phạm sự phân tách các mối quan tâm.

- Tạo tệp Javascript Các tính năng thu nhỏ rõ ràng đang có trong .NET 4.5 . Nếu bạn đi theo con đường không phô trương, sẽ không có bất cứ điều gì ngăn bạn tải tất cả các tệp JS trong 1 tập lệnh. Tôi sẽ cẩn thận về việc tạo các tệp JS khác nhau cho từng loại thực thể, bạn sẽ kết thúc với vụ nổ tệp JS. Hãy nhớ rằng, khi tệp tập lệnh của bạn được tải, trình duyệt sẽ lưu nó vào bộ đệm cho các yêu cầu trong tương lai.

- Các truy vấn phức tạp Tôi không coi việc có tính năng như phân trang, sắp xếp, v.v., là phức tạp. Sở thích của tôi là xử lý vấn đề này với logic của URL và phía máy chủ, để làm cho các truy vấn db bị giới hạn khi cần. Tuy nhiên, chúng tôi được triển khai lên Azure, vì vậy tối ưu hóa truy vấn rất quan trọng đối với chúng tôi. Ví dụ : /widgets/show-{pageSize}-per-page/page-{pageNumber}/sort-by-{sortColumn}-{sortDirection}/{keyword}. EF và LINQ to Entities có thể xử lý phân trang và sắp xếp theo các phương thức như .Take (), .Skip (), .OrderBy () và .OrderByDesceinating (), để bạn có được những gì bạn cần trong chuyến đi db. Tôi chưa tìm thấy nhu cầu về clientlib, vì vậy tôi thực sự không biết nhiều về họ. Nhìn vào câu trả lời khác để được tư vấn thêm về điều đó.

- Dự án lụa Chưa bao giờ nghe nói về điều này, sẽ phải kiểm tra nó. Tôi là một fan hâm mộ lớn của Steve Sanderson, những cuốn sách của anh ấy, BeginCollectionItem HtmlHelper và blog của anh ấy. Điều đó nói rằng, tôi không có bất kỳ kinh nghiệm nào với KnockoutJS trong sản xuất . Tôi đã xem hướng dẫn của nó, nhưng tôi cố gắng không cam kết điều gì cho đến khi ít nhất là phiên bản 2.0. Giống như tôi đã đề cập, KnockoutJS 2.0 vừa được phát hành.

- N-tier Nếu theo tầng, bạn có nghĩa là máy vật lý khác nhau, thì không, tôi không nghĩ bất cứ điều gì đi ra ngoài bất kỳ cửa sổ. Nói chung 3 tầng có nghĩa là bạn có 3 máy. Vì vậy, bạn có thể có một khách hàng béo làm tầng trình bày của mình, chạy trên máy của người dùng. Máy khách béo có thể truy cập một tầng dịch vụ, chạy trên máy chủ ứng dụng và trả về XML hoặc bất cứ thứ gì cho máy khách béo. Và tầng dịch vụ có thể lấy dữ liệu từ máy chủ SQL trên máy thứ 3.

MVC là một lớp, trên 1 tầng. Các bộ điều khiển, mô hình và khung nhìn của bạn đều là một phần của Lớp trình bày, là 1 lớp trong kiến ​​trúc vật lý. MVC thực hiện mẫu Model-View-Controller, đây là nơi bạn có thể thấy các lớp bổ sung. Tuy nhiên, cố gắng không nghĩ 3 khía cạnh này là tầng hoặc lớp. Hãy thử nghĩ cả 3 trong số chúng là Mối quan tâm của Lớp trình bày.

Cập nhật sau bình luận trước / xe buýt / dữ liệu

Được rồi, vì vậy bạn đang sử dụng lớp và lớp thay thế cho nhau. Tôi thường sử dụng thuật ngữ "lớp" cho các bộ phận logic / dự án / lắp ráp và tầng để phân tách mạng vật lý. Xin lỗi vì sự nhầm lẫn.

Bạn sẽ tìm thấy khá nhiều người trong trại MVC nói rằng bạn không nên sử dụng "Mô hình" trong MVC cho mô hình dữ liệu thực thể của mình, bạn cũng không nên sử dụng Bộ điều khiển cho logic nghiệp vụ. Lý tưởng nhất là các mô hình của bạn phải là ViewModels dành riêng cho chế độ xem. Sử dụng một cái gì đó như Automapper, bạn đưa các thực thể của mình từ mô hình miền của bạn và DTO chúng vào ViewModels, được điêu khắc đặc biệt để sử dụng cho chế độ xem.

Bất kỳ quy tắc kinh doanh nào cũng phải là một phần của miền của bạn và bạn có thể triển khai chúng bằng cách sử dụng các dịch vụ miền / mẫu nhà máy / bất cứ điều gì phù hợp trong lớp miền của bạn, không phải trong lớp trình bày MVC. Các bộ điều khiển nên câm, mặc dù không hoàn toàn ngu ngốc như các mô hình và nên giao trách nhiệm cho miền cho bất kỳ điều gì đòi hỏi kiến ​​thức kinh doanh. Bộ điều khiển quản lý luồng yêu cầu và phản hồi HTTP, nhưng bất kỳ thứ gì có giá trị kinh doanh thực sự đều phải cao hơn mức trả của bộ điều khiển.

Vì vậy, bạn vẫn có thể có một kiến ​​trúc phân lớp, với MVC là lớp trình bày. Nó là một ứng dụng khách của lớp ứng dụng, lớp dịch vụ hoặc lớp miền của bạn, tùy thuộc vào cách bạn kiến ​​trúc sư. Nhưng cuối cùng mô hình thực thể của bạn phải là một phần của miền, không phải mô hình trong MVC.


Tôi hoàn toàn đồng ý với câu trả lời này! Đặc biệt: • Resharper là một thiên tài MVC ... từ kiểm tra lỗi đến điều hướng IDE, tính hữu dụng của nó sẽ thổi bay tôi! • Server-Side MVC hầu như luôn là cách tiếp cận tốt nhất • MVC không phải là 3 tầng riêng biệt, nó là một lớp trình bày duy nhất - Tôi chưa bao giờ thực sự nghĩ về nó theo cách này, nhưng nó hoàn toàn chính xác.
Scott Rippey

Câu trả lời rất hay, chắc chắn là những gì tôi đang tìm kiếm với giá 300 rep của tôi. Đồ uống sẽ thuộc về tôi nếu bạn ở khu vực Toronto :)

btw Tôi luôn coi N-tier là Pres / Bus / Data bất kể họ ngồi ở đâu. Đó là lý do tại sao tôi nói MVC gần như loại bỏ kiến ​​trúc đó bởi vì về cơ bản nó kết hợp cả 3, những gì bạn nói có phần đồng ý với điều đó nhưng cũng đưa ra một quan điểm khác về nó.

Tôi sẽ cảnh báo chống lại cách tiếp cận ViewModel, model-per-view,. Gần đây tôi đã gặp phải tình huống mà sau này tôi ước rằng tôi không có sự trừu tượng hóa này từ DTO sang ViewModel. Xem: stackoverflow.com/q/7181980/109456

Theo nguyên tắc chung, tôi không muốn thấy jQuery và thay vào đó hãy viết các đối tượng có giao diện mà bất kỳ nhà phát triển phía máy chủ nào cũng có thể hiểu khá nhanh với JQ hoặc API DOM thực hiện công việc bên trong. Tôi cũng thực sự thích khái niệm URLConfig của Django và đã thấy nó hữu ích cho việc thiết lập các đối tượng để thực hiện trên các trang. Tôi không có ý tưởng gì về MV? thư viện được cho là để làm cho tôi mặc dù. Chúng không phù hợp hoàn hảo cho vấn đề này, IMO và đoàn sự kiện DOM + là tất cả mô hình tôi cần để xử lý các trang mà không bị ràng buộc quá mức với cấu trúc cụ thể.
Erik Reppen

6

Tôi sẽ không viết một câu trả lời đầy đủ, nhưng muốn chia sẻ một số mẹo.

Lời khuyên của tôi:

1. Cấu trúc dự án
Tôi thấy rằng cấu trúc MVC mặc định không tốt cho tôi. Tôi thường làm việc trong bộ điều khiển, khung nhìn và mô hình của cùng một thực thể (nghĩ về sản phẩm, đơn hàng, khách hàng) cùng một lúc. Vì vậy, tôi muốn có các tệp trong cùng một thư mục, nhưng với các không gian tên khác nhau.

2. Dữ liệu
Nếu bạn đi với Linq-to-SQL hoặc EF, bạn sẽ hối hận về sau.
Tôi sử dụng PetaPoco cho phép tôi chạy SQL lấy và cập nhật các bản ghi mà không bị đau bản đồ, nhưng không học một cách mới để làm mọi thứ và không gặp ác mộng về hiệu suất.

Tôi có một trình tạo mã để tạo lớp POCO ban đầu với các thuộc tính PetaPoco, sau đó thay đổi lớp khi một số trường được thêm hoặc xóa.

PetaPoco hoạt động với các lớp động và tiêu chuẩn, do đó bạn không có bất kỳ sự thỏa hiệp nào (Massive là tất cả động và Dapper tất cả các lớp tiêu chuẩn)

Tôi cũng tạo ra một tổng thể SQL, sử dụng được xây dựng trong SqlBuilder, có chứa tất cả các tiêu chuẩn tham gia cho các tổ chức, nhưng không có WHERE vì vậy tôi tái sử dụng SQL tương tự để lấy một tổ chức hoặc một danh sách.

3. Jquery Bạn có thể làm nổi bật một số phần của giao diện người dùng bằng cách sử dụng lệnh gọi jQuery chung (nhồi một số dữ liệu bên trong phần tử HTML).

Ví dụ, tôi có cái này để xóa.

var deleteLinkObj;
// delete Link
$('.jbtn-borrar').click(function () {
    deleteLinkObj = $(this);  //for future use
    $('#delete-dialog').dialog('open');
    return false; // prevents the default behaviour
});
$('#delete-dialog').dialog({
    autoOpen: false, width: 400, resizable: false, modal: true, //Dialog options
    buttons: {
        "Borrar": function () {
            $.post(deleteLinkObj[0].href, function (data) {  //Post to action
                if (data == 'OK') {
                    deleteLinkObj.closest("tr").hide('fast'); //Hide Row
                }
                else {
                    alert(data);
                }
            });
            $(this).dialog("close");
        },
        "Cancelar": function () {
            $(this).dialog("close");
        }
    }
});

Tôi chỉ cần thêm lớp jbtn-borrarvào một siêu liên kết và nó hiển thị một hộp thoại, xóa bản ghi và ẩntr

Nhưng đừng lật đổ nó. Ứng dụng của bạn sẽ tỏa sáng với những điểm nhấn nhỏ trong mỗi lần xem.

Máy khách MVC so với máy chủ MVC
Máy chủ MVC. Tận dụng các chế độ xem một phần mà bạn có thể sử dụng trong kết xuất ban đầu và làm mới một số phần với Ajax bằng cách sử dụng cùng một chế độ xem. Xem bài viết tuyệt vời này

Làm thế nào để xử lý các truy vấn phức tạp (hãy gọi nó là Báo cáo)
Tôi sử dụng một lớp có các tham số Báo cáo làm thuộc tính (thuận tiện cho việc sử dụng tự động hóa MVC) và một Generatephương thức thực hiện truy vấn và điền vào Danh sách lớp tùy chỉnh (nếu bạn không 't có một lớp phù hợp với ViewModel)
Bạn có thể sử dụng lớp này làm mô hình của khung nhìn và điền vào bảng với danh sách được tạo.

Dự án lụa của Microsoft
bao trùm. Chạy nhanh nhất có thể theo hướng ngược lại.


Thật buồn cười, khi tôi đọc qua Project Silk, tôi cứ cảm thấy khó chịu và tôi không thể đặt nó.

3

1. Cấu trúc dự án

Tôi có 2 tệp dự án trong giải pháp của mình

1) Lớp dịch vụ / doanh nghiệp Tôi đặt tất cả logic truy cập DB và mã truy cập DB và POCO vào dự án riêng biệt này. Không cần lớp Truy cập dữ liệu nếu bạn sử dụng ORM vì ORM đã trừu tượng hóa lớp DB.

2) Lớp UI chứa tất cả Chế độ xem, Bộ điều khiển, Mô hình, Tập lệnh, CSS của tôi

Tôi cố gắng làm cho các bộ điều khiển, Chế độ xem, tập lệnh và CSS của mình đều sử dụng cấu trúc thư mục tương tự. Đồng thời cấu trúc các tệp của tôi để khớp với đường dẫn URL càng nhiều càng tốt. Để tránh phải viết định tuyến tùy chỉnh.

Sử dụng DisplayTem mẫu, EditorTem mẫu, Chế độ xem một phần và thư mục được chia sẻ càng nhiều càng tốt.

Sau đó, tôi cấu trúc tất cả các Tập lệnh của mình để khớp với cùng một Vùng, Bộ điều khiển của các tệp c # của tôi Vì vậy, tôi sẽ có một tệp common.js ở gốc một tệp js trên mỗi trang và tệp common.js cho mỗi khu vực.

Các tệp CSS tôi thường có 2 + n (trong đó n là số vùng) Tệp CSS thứ nhất là CSS chỉ dành cho trang đích để giúp thời gian tải trang nhanh hơn (có lẽ không quá quan trọng đối với môi trường doanh nghiệp / doanh nghiệp) Tệp CSS thứ 2 là một common.css có tất cả các kiểu cho tất cả các trang khác. Sau đó, một tệp common.css khác cho từng khu vực, ví dụ như tệp AdminArea.css có CSS ​​cho mỗi trang quản trị.

2. Truy cập dữ liệu

Nếu tôi sử dụng Entity Framework, tôi sử dụng CodeFirst vì nó hoạt động rất tốt với POCOS và bạn không có mô hình để duy trì. nHibernate mạnh hơn nhiều nhưng có một lộ trình học tập từng bước. Để phân trang kết quả DB, tôi có một lớp c # có thể sử dụng lại và chế độ xem bằng sáng chế mà tôi sử dụng cho tất cả các chế độ xem của mình.

Đối với các truy vấn phức tạp và tạo báo cáo, tôi sử dụng các thủ tục được lưu trữ. Chúng dễ dàng hơn nhiều để viết và duy trì và cung cấp nhiều năng lượng hơn cho LINQ. Chúng cũng có thể được sử dụng lại bởi các dịch vụ khác như SSRS. Tôi sử dụng automapper để chuyển đổi tập dữ liệu được trả về để sử dụng toàn bộ khung công tác POCOs.

3. Tổ chức mã phía khách hàng và kết xuất giao diện người dùng

Câu trả lời của Eduardo Molteni có một mã ví dụ hay. Ngoài ra, tôi chắc chắn sẽ khuyên bạn nên sử dụng knoutoutjs vì nó có cả templating và ràng buộc tốt. Nếu bạn sử dụng JSON cho tất cả các cuộc gọi AJAX mà tôi sử dụng rất nhiều thì việc có bản đồ tự động UI tới các đối tượng JS là một trình tiết kiệm thời gian rất lớn.

Câu hỏi chung

Các truy vấn phức tạp nên sống trong một Proc được lưu trữ. (xem bình luận emeraldcode.com)

Bạn vẫn giữ kiến ​​trúc N tầng của mình bằng cách sử dụng MVC này.


1

Gần đây tôi đã rất xúc động khi tin rằng, nếu bạn có kế hoạch sử dụng ba công nghệ mà bạn đã liệt kê, trước tiên bạn nên bắt đầu bằng cách giả định áp dụng Orchard CMS . Tôi tin rằng đó là câu trả lời duy nhất tốt nhất cho yêu cầu trung tâm của bạn:

Chiến lược tối ưu để tổ chức mã và logic trong khi duy trì khả năng mở rộng và khả năng tạo giao diện người dùng phong phú, nhanh chóng, sạch sẽ là gì?

Trong kịch bản Ochard, bất cứ điều gì bạn không thể giải quyết thông qua các cơ chế cấu hình của nó, sau đó bạn sẽ xử lý thông qua việc bổ sung các mô-đun trực tuyến miễn phí hoặc viết mô-đun của riêng bạn (tất nhiên là C #, dao cạo, vân vân). Mã tổ chức là một thế mạnh của Orchard.

Đối với truy cập dữ liệu, có đủ ưu và nhược điểm đối với một ORM đầy đủ mà tôi cũng đã nghĩ rằng một ORM vi mô là cách tốt nhất. Hãy thử Massive hoặc Dapper . Cả hai đều được giới thiệu trên Hanselminutes . Tôi sẽ tóm tắt cả hai bằng cách nói điều này: các khái niệm trừu tượng từ SQL gần như bị phá vỡ khi dự án mở rộng. Cuối cùng, giải pháp tốt nhất để truy cập DB là sự trừu tượng hóa này được gọi là SQL (bit châm biếm, nhưng đúng). Hãy để micro-ORM hoạt động với điều đó và bạn đã có vàng.

Đặt Orchard cùng với các ORM siêu nhỏ và bạn có thể cắt thép như bơ. Er, có nghĩa là bạn có thể phát triển nhanh chóng, mở rộng quy mô và có mã có thể dễ dàng duy trì bởi một nhóm nhận được sự hỗ trợ.


0

Không chắc là tôi đã bỏ lỡ câu hỏi này như thế nào nhưng tôi sẽ thêm hai xu của mình hai năm sau.

MVC khách hàng so với máy chủ MVC? Dự án của tôi đã là một cấu trúc MVC phía máy chủ, vậy vẫn còn nhu cầu về MVC khách hàng như Backbone.js cung cấp?

MVC và MV? ngay cả trước khi nó bị đẩy sang phía khách hàng về cơ bản đã phát triển thành một thuật ngữ tiếp thị thực sự chỉ hứa rằng bằng cách nào đó dữ liệu sẽ được tách ra khỏi những thứ khác, một ý tưởng tuyệt vời nhưng không thực sự khó với DIY. Bất kể bạn đang thực hiện phương pháp nào, ngay trước hoặc ngay giữa khi thực hiện các thay đổi đối với HTML ảnh hưởng đến khả năng trình bày hoặc tương tác là nơi tuyệt vời nhất để sắp xếp những gì doanh nghiệp muốn bạn làm với dữ liệu.

Không có gì đặc biệt về "xem logic." Nguyên tắc tương tự nên áp dụng cho tất cả logic. Và đó là, đừng làm bất cứ điều gì bây giờ sẽ có ý nghĩa hơn nhiều để làm trước đây. Khi tất cả các con vịt của bạn liên tiếp trước khi bạn truyền một số dữ liệu hoặc bắt đầu một quy trình mới, giai đoạn trước đó có thể sẽ được sử dụng lại nhiều hơn cho bất kỳ điều gì khác trong hệ thống làm điều gì đó tương tự.

Các tệp Javascript có nên được tạo cho từng đối tượng (như OrderHeader.js) và sau đó được rút gọn / hợp nhất trong quá trình xây dựng không? Hoặc chỉ nên có một Order.js có logic cho OrderHeader, OrderDetails, Báo cáo, v.v.?

Điều đó thực sự tùy thuộc vào bạn nhưng tôi sẽ cố gắng thoát khỏi điều một tập tin, một lớp. Tôi chưa bao giờ hiểu tại sao nó hữu ích, chẳng hạn như phải tìm tệp trừu tượng và giao diện, và các tệp đang thực hiện, v.v ... Phân loại theo các mối quan tâm rộng hơn. ctrl + f không khó sử dụng nếu nó hơi lâu.

Điều đó nói rằng, bạn không bao giờ nên kết hợp lại JS để làm cho các tệp nhỏ hơn trên web. Các trình duyệt lưu bộ đệm JS để bạn chỉ cần tải lại cùng một JavaScript bằng cách dán mã cũ vào các tệp mới. Chặn số lượng JavaScript đáng kinh ngạc, lần duy nhất bạn không nên có tất cả các mã JavaScript trên trang là khi một số lượng rất lớn nó đặc biệt cao đối với một phần của trang web không có vùng chồng lấp / xám sẽ không bao giờ cần thiết trên một vùng nhất định trang.

Và FFS không phiền phức với việc quản lý phụ thuộc với JavaScript trên web. Require.js trên các trang web có độ phức tạp trung bình đến thấp khiến tôi muốn câu lạc bộ con dấu. Dán thư viện bên thứ ba của bạn trong một khối hàng đầu. Thư viện trong nhà của bạn trong khối thứ hai. Và sau đó, mã triển khai của bạn (không bao giờ là một phần mười miễn là mã thư viện trong nhà của bạn - tức là rất ngắn gọn và rõ ràng và dễ hiểu) trong bock thứ ba đó.

Làm thế nào các truy vấn phức tạp nên được xử lý? Ngay bây giờ, lý thuyết hàng đầu của tôi là / Báo cáo / Đơn hàng theo ngày / hoặc một cái gì đó dọc theo các dòng đó và tôi sử dụng truy vấn SQL tùy chỉnh để hiển thị một tập dữ liệu tùy chỉnh (hoặc ViewModel) cho Chế độ xem dao cạo. Nhưng những gì về phân trang, phân loại, vv? Điều này tốt hơn để được thực hiện phía khách hàng hoặc máy chủ? (giả sử tập dữ liệu lớn hơn - truy vấn SQL 2 đến 3 giây) Tôi đã đọc qua Project Silk của Microsoft. Đây có phải là một cách tốt để đi? Làm thế nào để nó so sánh với Backbone.js hoặc những người khác?

Thành thật mà nói, tôi muốn nói bất cứ điều gì dễ dàng hơn đối với bạn mà không gây khó chịu cho khách hàng. Các trang web tải khá nhanh về công nghệ hiện đại. Nếu việc triển khai trong Ajax gây nhiều đau đớn cho bạn, thì đừng. Chỉ cần đi với những gì bạn biết rõ nhất và sau đó bạn có thể trở nên ưa thích sau này và xem bạn thích nó như thế nào để phân trang. Nếu bạn đang xây dựng một ứng dụng phức tạp mới từ đầu, hãy bắt đầu với thiết yếu và nhấn gọn gàng sau.

Tôi đã rất quen với một kiến ​​trúc N tầng, những khái niệm này có phần nào ném nó ra ngoài cửa sổ không? Có vẻ như MVC giống như một loạt các phần N tầng nhỏ bên trong những gì sẽ là tầng trước hoặc tầng trên cùng trong quá khứ.

Nó thực sự phụ thuộc vào ý tưởng tưởng tượng của ai về MV nào? Là. IMO, điều vi mô có xu hướng hoạt động rất tốt. Một lớp các widget phân tách dữ liệu, giao tiếp và các nội dung liên quan đến chế độ xem bên trong hoạt động tuyệt vời. Trên trang web phía khách hàng, điều quan trọng, IMO, là duy trì sự cân bằng giữ các mối quan tâm tách biệt mà không cần phải phân chia thành các mối quan tâm nhỏ bé mà việc lắp lại gây khó khăn cho việc hiểu và sử dụng lại và sửa đổi mọi thứ. OOP "duh" cơ bản hoạt động tuyệt vời ở đây. Bạn không muốn các quy trình phức tạp. Bạn muốn rõ ràng được đặt tên những thứ có thể được di chuyển xung quanh và nói để làm công cụ. Dưới đây là một vài lời khuyên trên mặt trận đó:

  • Giao diện KISS đó (OOP) Tôi không muốn thấy DOM hoặc jQuery hoặc bất cứ thứ gì khác mà một nhà phát triển phía máy chủ bị chèn ép không thể tìm ra khá nhanh trong mã triển khai của tôi. Tất cả những gì người đó cần phải biết là lớp nào sẽ đập vào thùng chứa div và chuyển sang lật nào để tạo một bộ UI khá chung chung hoạt động trên một trang nhất định. Các biến thể về một chủ đề vẫn phải được thực hiện bằng cách chuyển vào các đối tượng tùy chọn được ghi thành tài liệu / nhận xét trước khi chúng phải bắt đầu xem tài liệu. Quên <bất cứ điều gì> hoặc hiểu bất cứ điều gì ngoài những điều cơ bản nhất của CSS.

  • Được rồi, làm thế nào để bạn làm điều đó? Vâng, chúng tôi đã có một mô hình. Nó được gọi là DOM. Và chúng tôi có đoàn sự kiện. Nếu bạn không tắt bong bóng sự kiện một cách bừa bãi (đừng làm vậy - nó ở đó vì nó hữu ích), bạn có thể nhặt từng chiếc ngay cả từ cơ thể nếu bạn muốn. Sau đó kiểm tra thuộc tính mục tiêu của đối tượng sự kiện đã thông qua và xác định ai chỉ là 'bất cứ điều gì'. Nếu bạn đang cấu trúc một tài liệu HTML một cách hợp lý thì không có lý do gì để không sử dụng nó làm mô hình ủy nhiệm. Hành vi và cấu trúc nội dung được liên kết tự nhiên. Cả hai đều có số nhận dạng chồng chéo.

  • Đừng trả tiền cho liên kết dữ liệu Và bằng cách "trả tiền", tất nhiên tôi có nghĩa là "đưa một thư viện vào cơ sở mã của bạn để khẳng định bạn làm mọi thứ chỉ vì vậy mọi lúc để có được một lợi ích kỳ diệu mà thực sự không khó để DIY." Hệ thống sự kiện của JQ làm cho nó khá dễ dàng.

Thời gian ví dụ:

function PoliticianData(){ //a constructor

    var
        that = this, //I hate 'that' but example so convention

        flavorsOfLie = {

            lies: "Oh Prism? Psh... no we're all good. There's a guy keeping an eye on that.",

            damnedLies: "50% of the people chose to not give a damn when asked whether it was better to let the terrorists win or not give a damn."

        }
    ;//end instance vars

    this.updateLies = function( lieType, newData ){
        flavorsOfLie[lieType] = newData;
        $(that).trigger({type:'update', lieType:lieType, newData: newData });
    }

    //so everytime you use the updateLies method, we can have a listener respond
    //and pass the data
}

var filthyLies = new PoliticianData();

$(filthyLies).on('update', function(e){
    stickNewDataInHTMLWithSomeFuncDefinedElsewhere(e.lieType, e.newData);
} );

filthyLies.update('damnedLies','50% of the people said they didn\'t give a damn');
//oh look, WaPo's front page just changed!
  • Không che giấu Web Nguồn chính của kẻ hút trong tất cả các nỗ lực ban đầu để làm cho phía máy khách dễ dàng cho phía máy chủ và nhà phát triển ứng dụng xoay quanh điểm quan trọng này. Yêu cầu HTTP không và không bao giờ phức tạp. Họ đã không yêu cầu một lớp 18! @ # $ Ing khó hiểu về tên sự kiện ở mỗi giai đoạn để làm cho nó dễ hiểu hơn. Tương tự như vậy, có rất nhiều điều cần biết về phía khách hàng nhưng không có lý do gì để trốn tránh HTML và DOM tương tác với nó bằng cách đặt một mô hình khổng lồ lớn lên trên nó. Nó đã là một mô hình khổng lồ lớn và nó hoạt động rất tốt. Tất cả những gì chúng ta cần để làm cho nó dễ quản lý hơn một chút là một số thực tiễn OOP hợp lý và một số kiến ​​thức về JS và DOM.

  • Ưu tiên linh hoạt

EXTjs <==== thang đo linh hoạt ====> jQuery (không nhất thiết là bất kỳ trình cắm nào của nó)

IMO, các công cụ cho phép bạn DIY nhanh chóng luôn là lựa chọn tốt hơn. Các công cụ đã làm tất cả cho bạn chỉ là lựa chọn đúng đắn khi không ai trên đầu bạn đặc biệt kén chọn các chi tiết và bạn không ngại nhường lại quyền kiểm soát cho chính điều được cho là sẽ giúp bạn. Tôi thực sự đã thấy các plugin xác thực HTML để đảm bảo bạn không lén lút một loại phần tử khác với tất cả các đặc điểm hiển thị chính xác giống nhau trong đó. Tại sao? Tôi chỉ có lý thuyết. Tôi nghĩ rằng những người hoàn thành thực sự ghét ý tưởng về việc ai đó sử dụng công cụ của họ theo cách không có ý định và đó luôn luôn là điều chắc chắn ai đó muốn bạn làm trong UI.

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.