TerryR arkadaşım, sen ve ben bir şeyler içmeliyiz. Bazı benzer problemlerimiz var.
1. Proje Yapısı: Eduardo ile bir MVC uygulamasındaki klasör yapısının arzulanan bir şey bıraktığını kabul ediyorum. Standart Kontrol Cihazları, Modelleri ve Görünümleri klasörleriniz var. Ancak, Görüntüler klasörü her Denetleyici için ayrı bir klasöre, ayrıca bir Paylaşılan klasöre bölünür. Ve her Görünüm / DenetleyiciAdı veya Görünüm / Paylaşılan, EditorTemplates ve DisplayTemplates öğelerine ayrılabilir. Ancak, Modeller klasörünüzü nasıl düzenleyeceğinize karar vermenize olanak tanır (alt klasörler veya alt adlar ve ek ad alanı bildirimleri ile yapabilirsiniz).
Tanrı, her bir alan için Denetleyicileri, Modelleri ve Görünümleri klasör yapısını çoğaltan Alanları kullanmanızı yasaklamaktadır.
/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
Bunun anlamı, eğer bir WidgetController gibi bir şeyle çalışıyorsanız, ilgili WidgetViewModels, WidgetViews, WidgetEditorTemplates, WidgetDisplayTemplates, vb. Bulmak için diğer klasörlere bakmanız gerekir. bu MVC sözleşmeleri. Aynı klasöre model, kontrolör ve görünüm koymak, ancak farklı ad alanlarıyla, ReSharper kullandığım için bundan kaçınıyorum. Squiggly, sınıfın bulunduğu klasörle eşleşmeyen bir ad alanının altını çizer. Bu R # özelliğini kapatabileceğimi biliyorum, ancak projenin diğer bölümlerinde yardımcı oluyor.
Sınıf dışı dosyalar için, MVC size kutudan İçerik ve Komut Dosyaları verir. Konvansiyonu takip etmek için tüm statik / derlenmemiş dosyalarımızı bu yerlerde tutmaya çalışıyoruz. Temaları kullanan bir js kütüphanesini her eklediğimizde (resimler ve veya css), tema dosyaları / içeriğin altında bir yere gider. Betik için hepsini doğrudan / betiklere koyarız. Başlangıçta bu, JS'nin VS'den intellisense'ini almaktı, ancak şimdi / # komutlarına yerleştirmeden bağımsız olarak JS # Rlis'ten intellisense'i alıyoruz, sanırım bundan sapabilir ve komut dosyalarını daha iyi organize etmek için klasöre bölebiliriz. ReSharper kullanıyor musunuz? Saf altın IMO.
Yeniden yapılandırmaya çok yardımcı olan bir başka altın parçası da T4MVC'dir. Bunu kullanarak, alan adları, denetleyici adları, işlem adları, hatta içerik ve komut dosyalarındaki dosyalar için dize yollarını girmemize gerek yoktur. T4MVC, sizin için tüm sihirli dizeleri güçlü bir şekilde yazıyor. İşte T4MVC kullanıyorsanız, proje yapınızın nasıl bir önemi olmadığını gösteren küçük bir örnek:
// 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. Veri erişimi: PetaPoco ile hiç bir tecrübem yok, ancak kontrol etmeye değer olduğuna eminim. Karmaşık raporlarınız için SQL Server Raporlama servislerini düşündünüz mü? Veya farklı bir db ile mi çalışıyorsunuz? Üzgünüm tam olarak ne istediğin konusunda net değilim. EF + LINQ kullanıyoruz, ancak etki alanı sınıflarında nasıl rapor oluşturulacağı konusunda da bazı bilgiler veriyoruz. Bu nedenle, doğrudan denetleyici çağrı havuzuna sahip olmak yerine denetleyici çağrı etki alanı servis çağrısı deposuna sahibiz. Geçici raporlar için, yine mükemmel olmayan SQL Reporting Services'ı kullanıyoruz, ancak kullanıcılarımız Excel'e kolayca veri sağlayabilmek istiyor ve SSRS bu işi kolaylaştırıyor.
3. Müşteri Tarafındaki Kod Organizasyonu ve Kullanıcı Arayüzü Oluşturma: Burası, size yardımcı olabileceğimi düşündüğüm yer. MVC göze batmayan doğrulama ve göze çarpmayan AJAX kitabından bir sayfa alın. Bunu düşün:
<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" />
Şimdilik ajax başarı fonksiyonunu dikkate almayın (bundan sonra daha fazlası için). Bazı eylemleriniz için tek bir komut dosyası ile kurtulabilirsiniz:
$('.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();
}
}
}
});
}
});
Yukarıdaki kod, onaylayıcıyı gösterir, döndürücüyü gösterir, bekleme mesajını gösterir ve ajax çağrısı tamamlandıktan sonra döndürücü / bekleme mesajını gizler. Davranışları, mütevazi kütüphaneler gibi data- * niteliklerini kullanarak yapılandırırsınız.
Genel Sorular
- İstemci MVC'sine karşı sunucu MVC? Başarı işlevinde gerçekleştirdiğiniz eylemleri sınırlandırmaya çalışmadım çünkü kontrol cihazınız JSON'a dönüyor gibi görünüyor. Denetleyicileriniz JSON’u iade ediyorsa, KnockoutJS’a bakmak isteyebilirsiniz. Nakavt JS sürüm 2.0 bugün piyasaya sürüldü . JSON'unuza doğrudan bağlanabilir, böylece gözlemlenebilir bir tıklama otomatik olarak javascript şablonlarınıza verileri bağlayabilir. Diğer yandan, ajax eylem yöntemlerinin JSON yerine HTML döndürmesini istemiyorsanız, önceden oluşturulmuş UL'i LI çocuklarıyla birlikte döndürebilirler ve bunu data-myapp-response = komutunu kullanarak bir öğeye ekleyebilirsiniz. "Sonuçlar". Başarı fonksiyonunuz daha sonra şöyle görünür:
success: function(html) {
var responseId = $(clicked).data('myapp-response');
if (responseId) {
$('#' + responseId).empty().html(html);
}
}
Bunun için en iyi cevabımı özetlemek gerekirse, JSON'u eylem yöntemlerinden döndürmeniz gerekiyorsa, sunucu tarafı Görünümü atlıyorsunuz, yani bu gerçekten sunucu MVC'si değil - sadece MC. PartialViewResult komutunu html ile ajax çağrılarına döndürürseniz, bu sunucu MVC'sidir. Bu nedenle, uygulamanız ajax aramaları için JSON verilerini döndürmek zorundaysa, KnockoutJS benzeri bir istemci MVVM kullanın.
Her iki durumda da, düzeninizi (html etiketlerini) davranışla (eşzamansız veri yükleme) karıştırdığı için gönderdiğiniz JS'yi sevmiyorum. Kısmi html görünümüne sahip sunucu MVC'sini veya saf JSON viewmodel verisine sahip istemci MVVM'yi seçmek sizin için bu sorunu çözecektir, ancak javascript'te DOM / HTML'yi el ile oluşturmak endişelerin ayrılmasını ihlal ediyor.
- Javascript dosyası oluşturma Görünüşe göre minyatür özellikleri .NET 4.5'te geliyor . Göze çarpmayan rotaya giderseniz, tüm JS'nizi 1 kod dosyasına yüklemenizi engelleyen hiçbir şey olmamalıdır. Her varlık türü için farklı JS dosyaları oluşturma konusunda dikkatli olurdum, JS dosya patlamasıyla bitirdiniz. Komut dosyanız bir kez yüklendiğinde, tarayıcının gelecekteki istekler için önbelleğe alması gerektiğini unutmayın.
- Karmaşık sorgular Sayfalandırma, sıralama vb. Gibi özelliklerin karmaşık olduğunu düşünmüyorum. Tercihim, URL'leri ve sunucu tarafı mantığını kullanmak, db sorgularını gerektiği kadar sınırlandırmak. Ancak, Azure'a konuşlandırıldık, bu nedenle sorgu optimizasyonu bizim için önemlidir. Örneğin: /widgets/show-{pageSize}-per-page/page-{pageNumber}/sort-by-{sortColumn}-{sortDirection}/{keyword}
. EF ve LINQ to Entities, sayfalama ve sıralama işlemlerini .Take (), .Skip (), .OrderBy () ve .OrderByDescending () gibi yöntemlerle işleyebilir, böylece db gezisi sırasında ihtiyacınız olanı elde edersiniz. Henüz bir clientlib ihtiyacı bulamadım, bu yüzden dürüstçe onlar hakkında fazla bir şey bilmiyorum. Bu konuda daha fazla tavsiye için diğer cevaplara bakın.
- Proje ipeği Hiç duymadım, kontrol etmek zorunda kalacak. Steve Sanderson, kitapları, BeginCollectionItem HtmlHelper ve blogunun büyük bir hayranıyım. Bu, üretimde KnockoutJS ile hiçbir deneyimim olmadığını söyledi . Öğreticilerine baktım, ancak en azından 2.0 sürümü olana kadar bir şey yapmamaya çalışıyorum. Bahsettiğim gibi, KnockoutJS 2.0 yeni piyasaya sürüldü.
- N-katmanlı Eğer farklı fiziksel makine demek istiyorsan, o zaman hayır, hiçbir şeyin bir pencereden dışarı çıkacağını sanmıyorum. Genellikle 3 katmanlı, 3 makineniz olduğunu gösterir. Dolayısıyla, sunum katmanınız olarak bir kullanıcının makinesinde çalışan şişman bir müşteriniz olabilir. Şişman istemci, bir uygulama sunucusunda çalışan ve XML'i veya ne olursa olsun, yağ istemcisine döndüren bir hizmet katmanına erişebilir. Ve hizmet katmanı verilerini 3. makinedeki bir SQL sunucusundan alabilir.
MVC, 1 katmanlı bir katmandır. Denetleyicileriniz, modelleriniz ve görünümleriniz, fiziksel mimaride 1 katmanlı olan Sunum Katmanınızın bir parçasıdır. MVC, ilave katmanlar görebileceğiniz Model-View-Controller desenini uygular. Ancak, bu 3 yönü katmanlar veya katmanlar olarak düşünmemeye çalışın. Bunların üçünü de Sunum Katmanı Endişeleri olarak düşünmeye çalışın.
Pres / bus / data yorumundan sonra güncelleme
Tamam, yani katmanlı ve katmanı birbirinin yerine kullanıyorsunuz. Genellikle "katman" terimini mantıksal / proje / montaj bölümleri için ve fiziksel ağ ayrımı için kullanılır. Karışıklık için özür dilerim.
MVC kampında, varlık veri modeliniz için MVC'deki "Modelleri" kullanmamanız gerektiğini veya Kontrol Cihazlarınızı iş mantığı için kullanmamanız gerektiğini söyleyen epeyce insan bulacaksınız. İdeal olarak, modelleriniz görünüme özgü ViewModels olmalıdır. Automapper gibi bir şey kullanarak, varlıklarınızı etki alanı modelinizden alır ve DTO'yu ViewModels'e görüntüler, özellikle görünüm tarafından kullanılmak üzere şekillendirilir.
Herhangi bir iş kuralı ayrıca etki alanınızın bir parçası olmalıdır ve bunları MVC sunum katmanında değil, etki alanı katmanınıza uygun olan etki alanı hizmetleri / fabrika modeli / uygun olanını kullanarak uygulayabilirsiniz. Kontrolörler aptal olmalı, model kadar aptal olmasalar ve işletme bilgisi gerektiren her şey için etki alanına sorumluluk vermelidirler. Kontrolörler, HTTP isteklerinin ve yanıtlarının akışını yönetir, ancak gerçek ticari değeri olan herhangi bir şey kontrol cihazının ödeme derecesinin üzerinde olmalıdır.
Böylece, sunum katmanı olarak MVC ile katmanlı bir mimariye sahip olabilirsiniz. Uygulama katmanınızın, hizmet katmanınızın veya etki alanı katmanınızın müşterisidir, nasıl tasarladığınıza bağlı olarak. Ancak sonuçta varlık modeliniz, MVC'deki modeller değil, alanın bir parçası olmalıdır.