Özel Bir Veritabanı Odaklı Site Haritası Sağlayıcısı Oluşturma (C#)
tarafından Scott Mitchell
ASP.NET 2.0'daki varsayılan site haritası sağlayıcısı, verilerini statik xml dosyasından alır. XML tabanlı sağlayıcı birçok küçük ve orta ölçekli Web sitesi için uygun olsa da, daha büyük Web uygulamaları daha dinamik bir site haritası gerektirir. Bu öğreticide, verilerini İş Mantığı Katmanı'ndan alan ve veritabanından veri alan özel bir site haritası sağlayıcısı oluşturacağız.
Giriş
ASP.NET 2.0 s site haritası özelliği, sayfa geliştiricinin bir web uygulamasının site haritasını XML dosyası gibi kalıcı bir ortamda tanımlamasını sağlar. Tanımlandıktan sonra, site haritası verilerine ad alanında sınıfıSystem.Web
aracılığıyla SiteMap
veya SiteMapPath, Menü ve TreeView denetimleri gibi çeşitli gezinti Web denetimleri aracılığıyla program aracılığıyla erişilebilir. Site haritası sistemi, farklı site haritası serileştirme uygulamalarının oluşturulabilmesi ve bir web uygulamasına eklenebilmesi için sağlayıcı modelini kullanır. ASP.NET 2.0 ile birlikte gelen varsayılan site haritası sağlayıcısı, site eşleme yapısını bir XML dosyasında kalıcı hale getirir. Ana Sayfalar ve Site Gezintisi öğreticisinde, bu yapıyı içeren ve XML'sini her yeni öğretici bölümüyle güncelleştiren adlı Web.sitemap
bir dosya oluşturduk.
Site haritasının yapısı bu öğreticiler gibi oldukça statikse, varsayılan XML tabanlı site haritası sağlayıcısı iyi çalışır. Ancak birçok senaryoda daha dinamik bir site haritası gerekir. Şekil 1'de gösterilen ve her kategorinin ve ürünün web sitesinin yapısında bölümler olarak göründüğü site haritasını göz önünde bulundurun. Bu site haritasıyla, kök düğüme karşılık gelen web sayfasını ziyaret etmek tüm kategorileri listeleyebileceğinden, belirli bir kategorinin web sayfasını ziyaret etmek söz konusu kategorinin ürünlerini listeler ve belirli bir ürünün web sayfasını görüntülemek söz konusu ürünün ayrıntılarını gösterir.
Şekil 1: Kategoriler ve Ürünler Site Haritası Yapısını Makyajla (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Bu kategori ve ürün tabanlı yapı dosyaya Web.sitemap
sabit kodlanmış olsa da, bir kategori veya ürün her eklendiğinde, kaldırıldığında veya yeniden adlandırıldığında dosyanın güncelleştirilmesi gerekir. Sonuç olarak, yapısı veritabanından veya ideal olarak uygulama mimarisinin İş Mantığı Katmanı'ndan alınırsa site haritası bakımı büyük ölçüde basitleştirilir. Bu şekilde, ürünler ve kategoriler eklendikçe, yeniden adlandırıldıkça veya silindikçe site haritası bu değişiklikleri yansıtacak şekilde otomatik olarak güncelleştirilir.
ASP.NET 2.0 s site haritası serileştirmesi sağlayıcı modelinin üzerinde oluşturulduğundan, verilerini veritabanı veya mimari gibi alternatif bir veri deposundan alan kendi özel site haritası sağlayıcımızı oluşturabiliriz. Bu öğreticide BLL'den verilerini alan özel bir sağlayıcı oluşturacağız. Haydi başlayalım!
Not
Bu öğreticide oluşturulan özel site haritası sağlayıcısı, uygulamanın mimarisine ve veri modeline sıkı bir şekilde bağlıdır. Jeff Prosise Site Haritalarını SQL Server veBeklediğiniz SQL Site Haritası Sağlayıcısı makalelerinde site haritası verilerini SQL Server depolamaya yönelik genelleştirilmiş bir yaklaşımı inceler.
1. Adım: Özel Site Haritası Sağlayıcısı Web Sayfaları Oluşturma
Özel site haritası sağlayıcısı oluşturmaya başlamadan önce bu öğretici için ihtiyacımız olan ASP.NET sayfalarını ekleyelim. adlı SiteMapProvider
yeni bir klasör ekleyerek başlayın. Ardından, aşağıdaki ASP.NET sayfaları bu klasöre ekleyerek her sayfayı ana sayfayla ilişkilendirdiğinizden Site.master
emin olun:
Default.aspx
ProductsByCategory.aspx
ProductDetails.aspx
Ayrıca klasöre App_Code
bir CustomProviders
alt klasör ekleyin.
Şekil 2: Site Haritası Provider-Related Öğreticileri için ASP.NET Sayfaları Ekleme
Bu bölüm için yalnızca bir öğretici olduğundan, bölümün öğreticilerini listelememiz gerekmez Default.aspx
. Bunun yerine, Default.aspx
kategorileri GridView denetiminde görüntüler. Bunu 2. Adımda ele alacağız.
Ardından, sayfaya bir başvuru eklemek için güncelleştirin Web.sitemap
Default.aspx
. Özellikle, Önbelleğe Alma'nın <siteMapNode>
ardından aşağıdaki işaretlemeyi ekleyin:
<siteMapNode
title="Customizing the Site Map" url="~/SiteMapProvider/Default.aspx"
description="Learn how to create a custom provider that retrieves the site map
from the Northwind database." />
güncelleştirdikten Web.sitemap
sonra, öğreticiler web sitesini bir tarayıcı üzerinden görüntülemek için biraz zaman ayırın. Sol taraftaki menüde artık tek site haritası sağlayıcısı öğreticisi için bir öğe yer alır.
Şekil 3: Site Haritası Artık Site Haritası Sağlayıcısı Öğreticisi için Bir Giriş Içeriyor
Bu öğreticinin ana odak noktası, özel bir site haritası sağlayıcısı oluşturma ve bu sağlayıcıyı kullanmak üzere bir web uygulaması yapılandırmayı göstermektir. Özellikle, Şekil 1'de gösterildiği gibi her kategori ve ürün için bir düğümle birlikte kök düğüm içeren bir site haritası döndüren bir sağlayıcı oluşturacağız. Genel olarak, site haritasındaki her düğüm bir URL belirtebilir. Site haritamız için kök düğümün URL'si ~/SiteMapProvider/Default.aspx
olur ve bu url veritabanındaki tüm kategorileri listeler. Site haritasındaki her kategori düğümü, belirtilen categoryID'deki tüm ürünleri listeleyen öğesine işaret eden bir URL'ye~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
sahip olur. Son olarak, her ürün sitesi haritası düğümü belirli ürün ayrıntılarını görüntüleyen öğesini işaret ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID
eder.
Başlamak için , ProductsByCategory.aspx
ve ProductDetails.aspx
sayfalarını oluşturmamız Default.aspx
gerekir. Bu sayfalar sırasıyla Adım 2, 3 ve 4'te tamamlanır. Bu öğreticinin itici gücü site haritası sağlayıcılarında olduğundan ve geçmiş öğreticiler bu tür çok sayfalı ana/ayrıntı raporları oluşturmayı kapsadığından, 2- 4 arası adımlarda acele edeceğiz. Birden çok sayfaya yayılan ana/ayrıntı raporları oluşturma konusunda yenileyiciye ihtiyacınız varsa, İki Sayfada Ana/Ayrıntı Filtreleme öğreticisine geri bakın.
2. Adım: Kategori Listesi Görüntüleme
Klasördeki SiteMapProvider
sayfayı Default.aspx
açın ve Araç Kutusu'ndan bir GridView'ı Tasarım Aracı sürükleyip olarak ID
Categories
ayarlayın. GridView'un akıllı etiketinden bunu adlı CategoriesDataSource
yeni bir ObjectDataSource'a bağlayın ve sınıfın GetCategories
yöntemini kullanarak CategoriesBLL
verilerini alacak şekilde yapılandırın. Bu GridView yalnızca kategorileri görüntülediğinden ve veri değiştirme özellikleri sağlamadığından, UPDATE, INSERT ve DELETE sekmelerindeki açılan listeleri (Yok) olarak ayarlayın.
Şekil 4: Yöntemi Kullanarak ObjectDataSource'un Kategorileri Döndürecek Şekilde Yapılandırılması GetCategories
(Tam boyutlu görüntüyü görüntülemek için tıklayın)
Şekil 5: UPDATE, INSERT ve DELETE Sekmelerindeki Drop-Down Listeler (Yok) olarak ayarlayın (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Veri Kaynağını Yapılandırma sihirbazını tamamladıktan sonra Visual Studio , , CategoryName
, NumberOfProducts
Description
ve BrochurePath
için CategoryID
bir BoundField ekler. GridView'ı yalnızca ve BoundField'lerini barındıracak CategoryName
şekilde düzenleyin ve BoundField s HeaderText
özelliğini Category olarak güncelleştirinCategoryName
.Description
Ardından, bir HyperLinkField ekleyin ve en soldaki alan olacak şekilde konumlandırın. DataNavigateUrlFields
özelliğini ve CategoryID
DataNavigateUrlFormatString
özelliğini ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}
olarak ayarlayın. Text
özelliğini Ürünleri Görüntüle olarak ayarlayın.
Şekil 6: GridView'a Categories
HyperLinkField ekleme
ObjectDataSource'ı oluşturduktan ve GridView alanlarını özelleştirdikten sonra iki denetim bildirim temelli işaretleme aşağıdaki gibi görünür:
<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False"
DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource"
EnableViewState="False">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="CategoryID"
DataNavigateUrlFormatString=
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}"
Text="View Products" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description"
SortExpression="Description" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"
TypeName="CategoriesBLL"></asp:ObjectDataSource>
Şekil 7'de tarayıcı üzerinden görüntülendiğinde gösterilmektedir Default.aspx
. Bir kategorinin Ürünleri Görüntüle bağlantısına ProductsByCategory.aspx?CategoryID=categoryID
tıklanması sizi 3. Adımda oluşturacağımız adresine götürür.
Şekil 7: Her Kategori, Ürünleri Görüntüle Bağlantısıyla Birlikte Listelenir (Tam boyutlu görüntüyü görüntülemek için tıklayın)
3. Adım: Seçili Kategorinin Ürünlerini Listeleme
Sayfayı ProductsByCategory.aspx
açın ve adını vererek ProductsByCategory
bir GridView ekleyin. Akıllı etiketinden GridView'ı adlı ProductsByCategoryDataSource
yeni bir ObjectDataSource'a bağlayın. ObjectDataSource'ı GetProductsByCategoryID(categoryID)
sınıf yöntemini kullanacak ProductsBLL
şekilde yapılandırın ve UPDATE, INSERT ve DELETE sekmelerinde açılan listeleri (Yok) olarak ayarlayın.
Şekil 8: Sınıf GetProductsByCategoryID(categoryID)
Yöntemini kullanma ProductsBLL
(Tam boyutlu görüntüyü görüntülemek için tıklayın)
Veri Kaynağını Yapılandırma sihirbazındaki son adım , categoryID için bir parametre kaynağı ister. Bu bilgiler querystring alanından CategoryID
geçirildiğinden, açılan listeden QueryString'i seçin ve Şekil 9'da gösterildiği gibi QueryStringField metin kutusuna CategoryID girin. Sihirbazı tamamlamak için Son’a tıklayın.
Şekil 9: categoryID Parametresi için Sorgu Dizesi Alanını Kullanma CategoryID
(Tam boyutlu görüntüyü görüntülemek için tıklayın)
Sihirbazı tamamladıktan sonra Visual Studio, ürün veri alanları için GridView'a karşılık gelen BoundField'leri ve bir CheckBoxField'i ekler. , , UnitPrice
ve SupplierName
BoundFields dışında ProductName
tümünü kaldırın. Sırasıyla Product, Price ve Supplier değerlerini okumak için bu üç BoundFields HeaderText
özelliğini özelleştirin. BoundField'i UnitPrice
para birimi olarak biçimlendirin.
Ardından, bir HyperLinkField ekleyin ve en soldaki konuma taşıyın. Text
Özelliğini View Details, DataNavigateUrlFields
özelliğini olarak ProductID
ve DataNavigateUrlFormatString
özelliğini ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}
olarak ayarlayın.
Şekil 10: İşaret Eden Bir Görünüm Ayrıntıları HyperLinkField Ekleme ProductDetails.aspx
Bu özelleştirmeleri yaptıktan sonra GridView ve ObjectDataSource'un bildirim temelli işaretlemesi aşağıdakine benzer olmalıdır:
<asp:GridView ID="ProductsByCategory" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsByCategoryDataSource"
EnableViewState="False">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="ProductID"
DataNavigateUrlFormatString=
"~/SiteMapProvider/ProductDetails.aspx?ProductID={0}"
Text="View Details" />
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsByCategoryDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameter Name="categoryID"
QueryStringField="CategoryID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Tarayıcı üzerinden görüntülemeye Default.aspx
dönün ve İçecekler için Ürünleri Görüntüle bağlantısına tıklayın. Bu sizi, Northwind veritabanındaki İçecekler kategorisine ProductsByCategory.aspx?CategoryID=1
ait ürünlerin adlarını, fiyatlarını ve tedarikçilerini görüntüleyen bölümüne götürür (bkz. Şekil 11). Kullanıcıları kategori listesi sayfasına (Default.aspx
) döndürmek için bir bağlantı ve seçili kategorinin adını ve açıklamasını görüntüleyen detailsView veya FormView denetimini içerecek şekilde bu sayfayı daha da geliştirebilirsiniz.
Şekil 11: İçecek Adları, Fiyatları ve Tedarikçiler Görüntülenir (Tam boyutlu görüntüyü görüntülemek için tıklayın)
4. Adım: Bir Ürünün Ayrıntılarını Gösterme
Son sayfa olan ProductDetails.aspx
, seçili ürünlerin ayrıntılarını görüntüler. Araç Kutusundan bir DetailsView açın ProductDetails.aspx
ve Tasarım Aracı sürükleyin. DetailsView s özelliğini olarak ProductInfo
ayarlayın ve ve Width
özellik değerlerini temizleyinHeight
.ID
Akıllı etiketinden, DetailsView'ı adlı ProductDataSource
yeni bir ObjectDataSource'a bağlayın ve ObjectDataSource'ı sınıfının GetProductByProductID(productID)
yönteminden ProductsBLL
verilerini çekecek şekilde yapılandırın. 2. ve 3. Adımlarda oluşturulan önceki web sayfalarında olduğu gibi, UPDATE, INSERT ve DELETE sekmelerindeki açılan listeleri (Yok) olarak ayarlayın.
Şekil 12: ObjectDataSource'ı Yöntemi Kullanacak GetProductByProductID(productID)
Şekilde Yapılandırma (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Veri Kaynağını Yapılandırma sihirbazının son adımı productID parametresinin kaynağını sorar. Bu veriler querystring alanından ProductID
geldiğinden, açılan listeyi QueryString ve QueryStringField metin kutusunu ProductID olarak ayarlayın. Son olarak, sihirbazı tamamlamak için Son düğmesine tıklayın.
Şekil 13: ProductID Parametresini Sorgu Dizesi Alanından Değerini ProductID
Çekecek Şekilde Yapılandırma (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Veri Kaynağını Yapılandırma sihirbazını tamamladıktan sonra Visual Studio, ürün veri alanları için DetailsView'da karşılık gelen BoundField'ler ve bir CheckBoxField oluşturur. ProductID
, , SupplierID
ve CategoryID
BoundField değerlerini kaldırın ve kalan alanları uygun gördüğünüz şekilde yapılandırın. Birkaç estetik yapılandırmadan sonra DetailsView ve ObjectDataSource bildirim temelli işaretlemem aşağıdaki gibi görünüyordu:
<asp:DetailsView ID="ProductInfo" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ProductDataSource"
EnableViewState="False">
<Fields>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="Units In Stock"
SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder" HeaderText="Units On Order"
SortExpression="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel" HeaderText="Reorder Level"
SortExpression="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
<asp:ObjectDataSource ID="ProductDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductByProductID" TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameter Name="productID"
QueryStringField="ProductID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Bu sayfayı test etmek için İçecekler kategorisi için Ürünleri Görüntüle'ye Default.aspx
geri dönün ve tıklayın. İçecek ürünleri listesinden Chai Tea için Ayrıntıları Görüntüle bağlantısına tıklayın. Bu sizi ProductDetails.aspx?ProductID=1
Chai Tea s ayrıntılarını gösteren bölümüne götürür (bkz. Şekil 14).
Şekil 14: Chai Tea s Tedarikçi, Kategori, Fiyat ve Diğer Bilgiler Görüntüleniyor (Tam boyutlu görüntüyü görüntülemek için tıklayın)
5. Adım: Site Haritası Sağlayıcısının İç Çalışmalarını Anlama
Site haritası, web sunucusunun belleğinde hiyerarşi oluşturan örneklerin SiteMapNode
koleksiyonu olarak temsil edilir. Tam olarak bir kök olmalıdır, kök olmayan tüm düğümler tam olarak bir üst düğüme sahip olmalıdır ve tüm düğümler rastgele sayıda alt düğüme sahip olabilir. Her SiteMapNode
nesne web sitesinin yapısındaki bir bölümü temsil eder; bu bölümler genellikle buna karşılık gelen bir web sayfasına sahiptir. Sonuç olarak, sınıfınSiteMapNode
temsil ettiği bölüm SiteMapNode
için bilgi sağlayan , Url
ve Description
gibi Title
özellikleri vardır. Ayrıca, hiyerarşideki her SiteMapNode
bir özelliği ve bu hiyerarşiyi ChildNodes
oluşturmak için kullanılan özellikleri benzersiz olarak tanımlayan bir Key
özellik vardır , ParentNode
, NextSibling
, PreviousSibling
, vb.
Şekil 15'te Şekil 1'deki genel site haritası yapısı gösterilir, ancak uygulama ayrıntıları daha ayrıntılı bir şekilde çizilir.
Şekil 15: Her SiteMapNode
birinin , Url
, Key
ve Benzeri Gibi Title
Özellikleri Vardır (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Site haritasına ad alanındaSystem.Web
sınıfı üzerinden SiteMap
erişilebilir. Bu sınıf özelliği RootNode
, site haritasının kök SiteMapNode
örneğini döndürür; CurrentNode
özelliği şu anda istenen sayfanın URL'si ile eşleşen öğesini döndürür SiteMapNode
Url
. Bu sınıf, ASP.NET 2.0 s gezinti Web denetimleri tarafından dahili olarak kullanılır.
Sınıf özelliklerine SiteMap
erişildiğinde, site haritası yapısını kalıcı bir ortamdan belleğe seri hale getirmesi gerekir. Ancak, site haritası serileştirme mantığı sınıfına SiteMap
sabit kodlanmaz. Bunun yerine, serileştirme için hangi site haritası sağlayıcısının kullanılacağını çalışma zamanında SiteMap
sınıfı belirler. Varsayılan olarak, XmlSiteMapProvider
düzgün biçimlendirilmiş bir XML dosyasından site haritasının yapısını okuyan sınıfı kullanılır. Ancak, biraz çalışmayla kendi özel site haritası sağlayıcımızı oluşturabiliriz.
Tüm site haritası sağlayıcıları, site haritası sağlayıcıları için gerekli temel yöntemleri ve özellikleri içeren sınıfındanSiteMapProvider
türetilmelidir, ancak uygulama ayrıntılarının çoğunu atlar. İkinci sınıf olan StaticSiteMapProvider
, sınıfını SiteMapProvider
genişletir ve gerekli işlevselliğin daha sağlam bir uygulamasını içerir. dahili olarak, StaticSiteMapProvider
site haritasının örneklerini bir Hashtable
içinde depolar SiteMapNode
ve gibi RemoveNode(siteMapNode),
AddNode(child, parent)
yöntemler sağlar ve Clear()
iç öğesine s Hashtable
ekleyip kaldırırSiteMapNode
. XmlSiteMapProvider
, 'den StaticSiteMapProvider
türetilir.
genişleten StaticSiteMapProvider
bir özel site haritası sağlayıcısı oluştururken, geçersiz kılınması gereken iki soyut yöntem vardır: BuildSiteMap
ve GetRootNodeCore
. BuildSiteMap
adından da anlaşılacağı gibi, site haritası yapısını kalıcı depolama alanından yüklemekten ve bellekte oluşturmaktan sorumludur. GetRootNodeCore
, site haritasındaki kök düğümü döndürür.
Bir web uygulamasının site haritası sağlayıcısını kullanabilmesi için uygulamanın yapılandırmasına kaydedilmesi gerekir. Varsayılan olarak, XmlSiteMapProvider
sınıfı adı AspNetXmlSiteMapProvider
kullanılarak kaydedilir. Ek site haritası sağlayıcılarını kaydetmek için aşağıdaki işaretlemeyi öğesine Web.config
ekleyin:
<configuration>
<system.web>
...
<siteMap defaultProvider="defaultProviderName">
<providers>
<add name="name" type="type" />
</providers>
</siteMap>
</system.web>
</configuration>
Ad değeri sağlayıcıya insan tarafından okunabilir bir ad atarken, tür site haritası sağlayıcısının tam tür adını belirtir. Özel site haritası sağlayıcımızı oluşturduktan sonra 7. Adımda ad ve tür değerleri için somut değerleri keşfedeceğiz.
Site haritası sağlayıcı sınıfı, sınıfından ilk kez erişildiğinde SiteMap
örneği oluşturulur ve web uygulamasının ömrü boyunca bellekte kalır. Site haritası sağlayıcısının birden çok eşzamanlı web sitesi ziyaretçisinden çağrılabilecek tek bir örneği olduğundan, sağlayıcının yöntemlerinin iş parçacığı açısından güvenli olması zorunludur.
Performans ve ölçeklenebilirlik nedenleriyle, bellek içi site eşleme yapısını önbelleğe alıp yöntemin her çağrıldığında yeniden oluşturması yerine bu önbelleğe alınmış yapıyı BuildSiteMap
döndürmemiz önemlidir. BuildSiteMap
sayfada kullanılan gezinti denetimlerine ve site haritası yapısının derinliğine bağlı olarak, kullanıcı başına sayfa isteği başına birkaç kez çağrılabilir. Her durumda, site haritası yapısını BuildSiteMap
içinde önbelleğe almazsak, her çağrıldığında mimariden ürün ve kategori bilgilerini yeniden almamız gerekir (bu da veritabanında sorgu yapılmasına neden olur). Önceki önbelleğe alma öğreticilerinde ele aldığımız gibi önbelleğe alınan veriler eskitilebilir. Bununla mücadele etmek için zaman veya SQL önbelleği bağımlılık tabanlı süre sonu kullanabiliriz.
Not
Site haritası sağlayıcısı isteğe bağlı olarak yöntemini geçersiz kılabilirInitialize
. Initialize
, site haritası sağlayıcısı ilk kez başlatıldığında çağrılır ve öğesinde Web.config
<add>
sağlayıcıya atanmış olan özel öznitelikler geçirilir: <add name="name" type="type" customAttribute="value" />
. Bir sayfa geliştiricisinin sağlayıcının kodunu değiştirmek zorunda kalmadan site haritası sağlayıcısıyla ilgili çeşitli ayarları belirtmesine izin vermek istiyorsanız kullanışlıdır. Örneğin, kategori ve ürün verilerini mimarinin aksine doğrudan veritabanından okuyor olsaydık, sayfa geliştiricisinin sağlayıcı kodunda sabit kodlanmış bir değer kullanmak yerine veritabanı bağlantı dizesi Web.config
belirtmesine izin vermek isteyebiliriz. 6. Adımda oluşturacağımız özel site haritası sağlayıcısı bu Initialize
yöntemi geçersiz kılmaz. yöntemini kullanma Initialize
örneği için, SQL Server makalesinde Jeff ProsiseSite Haritalarını Depolama makalesine bakın.
6. Adım: Özel Site Haritası Sağlayıcısı Oluşturma
Northwind veritabanındaki kategorilerden ve ürünlerden site haritasını oluşturan özel bir site haritası sağlayıcısı oluşturmak için, öğesini genişleten StaticSiteMapProvider
bir sınıf oluşturmamız gerekir. 1. Adımda, klasörüne bir CustomProviders
klasör App_Code
eklemenizi istedim- bu klasöre adlı NorthwindSiteMapProvider
yeni bir sınıf ekleyin. Sınıfına NorthwindSiteMapProvider
aşağıdaki kodu ekleyin:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
public class NorthwindSiteMapProvider : StaticSiteMapProvider
{
private readonly object siteMapLock = new object();
private SiteMapNode root = null;
public const string CacheDependencyKey =
"NorthwindSiteMapProviderCacheDependency";
public override SiteMapNode BuildSiteMap()
{
// Use a lock to make this method thread-safe
lock (siteMapLock)
{
// First, see if we already have constructed the
// rootNode. If so, return it...
if (root != null)
return root;
// We need to build the site map!
// Clear out the current site map structure
base.Clear();
// Get the categories and products information from the database
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
// Create the root SiteMapNode
root = new SiteMapNode(
this, "root", "~/SiteMapProvider/Default.aspx", "All Categories");
AddNode(root);
// Create SiteMapNodes for the categories and products
foreach (Northwind.ProductsRow product in products)
{
// Add a new category SiteMapNode, if needed
string categoryKey, categoryName;
bool createUrlForCategoryNode = true;
if (product.IsCategoryIDNull())
{
categoryKey = "Category:None";
categoryName = "None";
createUrlForCategoryNode = false;
}
else
{
categoryKey = string.Concat("Category:", product.CategoryID);
categoryName = product.CategoryName;
}
SiteMapNode categoryNode = FindSiteMapNodeFromKey(categoryKey);
// Add the category SiteMapNode if it does not exist
if (categoryNode == null)
{
string productsByCategoryUrl = string.Empty;
if (createUrlForCategoryNode)
productsByCategoryUrl =
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID="
+ product.CategoryID;
categoryNode = new SiteMapNode(
this, categoryKey, productsByCategoryUrl, categoryName);
AddNode(categoryNode, root);
}
// Add the product SiteMapNode
string productUrl =
"~/SiteMapProvider/ProductDetails.aspx?ProductID="
+ product.ProductID;
SiteMapNode productNode = new SiteMapNode(
this, string.Concat("Product:", product.ProductID),
productUrl, product.ProductName);
AddNode(productNode, categoryNode);
}
// Add a "dummy" item to the cache using a SqlCacheDependency
// on the Products and Categories tables
System.Web.Caching.SqlCacheDependency productsTableDependency =
new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Products");
System.Web.Caching.SqlCacheDependency categoriesTableDependency =
new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Categories");
// Create an AggregateCacheDependency
System.Web.Caching.AggregateCacheDependency aggregateDependencies =
new System.Web.Caching.AggregateCacheDependency();
aggregateDependencies.Add(productsTableDependency, categoriesTableDependency);
// Add the item to the cache specifying a callback function
HttpRuntime.Cache.Insert(
CacheDependencyKey, DateTime.Now, aggregateDependencies,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.Normal,
new CacheItemRemovedCallback(OnSiteMapChanged));
// Finally, return the root node
return root;
}
}
protected override SiteMapNode GetRootNodeCore()
{
return BuildSiteMap();
}
protected void OnSiteMapChanged(string key, object value, CacheItemRemovedReason reason)
{
lock (siteMapLock)
{
if (string.Compare(key, CacheDependencyKey) == 0)
{
// Refresh the site map
root = null;
}
}
}
public DateTime? CachedDate
{
get
{
return HttpRuntime.Cache[CacheDependencyKey] as DateTime?;
}
}
}
Deyimiyle başlayan bu sınıfın BuildSiteMap
yöntemini keşfederek başlayalımlock
. lock
deyimi bir kerede yalnızca bir iş parçacığının girmesine izin verir, böylece koduna erişimi seri hale getirerek iki eşzamanlı iş parçacığının birbirine adım atmasını önler.
Sınıf düzeyi SiteMapNode
değişkeni root
, site eşleme yapısını önbelleğe almak için kullanılır. Site haritası ilk kez veya temel alınan veriler değiştirildikten sonra ilk kez oluşturulduğunda, root
null
olur ve site haritası yapısı oluşturulur. Bu yöntemin bir sonraki çağrılışında root
null
olmaması içinroot
, oluşturma işlemi sırasında site haritasının kök düğümüne atanır. Sonuç olarak, olmadığı sürece root
null
site haritası yapısı yeniden oluşturmak zorunda kalmadan çağırana döndürülür.
Kök ise null
, site haritası yapısı ürün ve kategori bilgilerinden oluşturulur. Site haritası, örnekleri oluşturarak ve ardından sınıfın SiteMapNode
AddNode
yöntemine yapılan çağrılar aracılığıyla hiyerarşiyi StaticSiteMapProvider
oluşturarak oluşturulur. AddNode
, çeşitli örnekleri bir Hashtable
içinde depolayarak SiteMapNode
iç muhasebe gerçekleştirir. Hiyerarşiyi oluşturmadan önce, iç Hashtable
öğesinden öğeleri temizleyen yöntemini çağırarak Clear
başlayacağız. Ardından, sınıfın ProductsBLL
GetProducts
yöntemi ve sonuç ProductsDataTable
yerel değişkenlerde depolanır.
Site haritasının yapısı, kök düğümü oluşturup öğesine root
atayarak başlar. Burada kullanılan s oluşturucununSiteMapNode
aşırı yüklemesi ve bu BuildSiteMap
işlem boyunca aşağıdaki bilgiler geçirilir:
- Site haritası sağlayıcısına (
this
) bir başvuru. - s
SiteMapNode
Key
. Bu gerekli değer herSiteMapNode
için benzersiz olmalıdır. - s
SiteMapNode
Url
.Url
isteğe bağlıdır, ancak sağlanırsa herSiteMapNode
değerinUrl
benzersiz olması gerekir. SiteMapNode
gerekli olan sTitle
.
yöntem AddNode(root)
çağrısı, SiteMapNode
root
site eşlemesine kök olarak öğesini ekler. Ardından içindeki her ProductRow
ProductsDataTable
biri numaralandırılır. Geçerli ürünün kategorisi için zaten bir SiteMapNode
varsa, buna başvurulur. Aksi takdirde, yöntem çağrısı aracılığıyla AddNode(categoryNode, root)
kategorisi için yeni SiteMapNode
bir oluşturulur ve öğesinin SiteMapNode``root
alt öğesi olarak eklenir. Uygun kategori SiteMapNode
düğümü bulunduktan veya oluşturulduktan sonra geçerli ürün için bir SiteMapNode
oluşturulur ve aracılığıyla AddNode(productNode, categoryNode)
kategorinin SiteMapNode
alt öğesi olarak eklenir. Kategorinin SiteMapNode
Url
özellik değerinin, ürün SiteMapNode
s Url
özelliği atanırken ~/SiteMapNode/ProductDetails.aspx?ProductID=productID
olduğuna ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
dikkat edin.
Not
Veritabanı CategoryID
değerlerine sahip NULL
olan ürünler, özelliği None olarak ayarlanmış ve Url
özelliği boş bir dize olarak ayarlanmış bir kategori SiteMapNode
Title
altında gruplandırılır. Sınıfın GetProductsByCategory(categoryID)
ProductBLL
yöntemi şu anda yalnızca bir değere sahip ürünleri döndürme yeteneğine sahip olmadığından boş birCategoryID
NULL
dizeye ayarlamaya Url
karar verdim. Ayrıca, gezinti denetimlerinin özelliği için Url
değer olmayan bir SiteMapNode
öğesini nasıl işlendiğini göstermek istedim. None SiteMapNode
s Url
özelliğinin öğesini işaret edebilmesi için ProductsByCategory.aspx
bu öğreticiyi genişletmenizi ve yalnızca değerleri olan NULL
CategoryID
ürünleri görüntülemenizi tavsiye ediyorum.
Site haritası oluşturulduktan sonra, bir nesne aracılığıyla ve Products
tablolarında SQL önbellek bağımlılığı kullanılarak veri önbelleğine Categories
rastgele bir AggregateCacheDependency
nesne eklenir. Önceki öğreticide SQL Önbelleği Bağımlılıklarını Kullanma bölümünde SQL önbellek bağımlılıklarını kullanmayı keşfettik. Ancak özel site haritası sağlayıcısı henüz araştırmadığımız veri önbelleği Insert
yönteminin aşırı yüklemesini kullanır. Bu aşırı yükleme, son giriş parametresi olarak nesne önbellekten kaldırıldığında çağrılan bir temsilci kabul eder. Özellikle, sınıfında daha aşağıda NorthwindSiteMapProvider
tanımlanan yönteme OnSiteMapChanged
işaret eden yeni CacheItemRemovedCallback
bir temsilci geçiririz.
Not
Site eşlemesinin bellek içi gösterimi sınıf düzeyi değişkeni root
aracılığıyla önbelleğe alınır. Özel site haritası sağlayıcı sınıfının yalnızca bir örneği olduğundan ve bu örnek web uygulamasındaki tüm iş parçacıkları arasında paylaşıldığından, bu sınıf değişkeni önbellek görevi görür. BuildSiteMap
Yöntemi ayrıca veri önbelleğini de kullanır, ancak yalnızca veya Products
tablolarındaki temel veritabanı verileri değiştiğinde Categories
bildirim almak için bir araç olarak kullanılır. Veri önbelleğine konan değerin yalnızca geçerli tarih ve saat olduğunu unutmayın. Gerçek site haritası verileri veri önbelleğine yerleştirilmemiştir .
yöntemi, BuildSiteMap
site haritasının kök düğümünü döndürerek tamamlar.
Kalan yöntemler oldukça basittir. GetRootNodeCore
kök düğümü döndürmekten sorumludur. Kök BuildSiteMap
döndürdüğünden, GetRootNodeCore
yalnızca dönüş değerini döndürür BuildSiteMap
. OnSiteMapChanged
yöntemiroot
, önbellek öğesi kaldırıldığında olarak ayarlanırnull
. Kök yeniden olarak null
ayarlandığında, bir sonraki BuildSiteMap
çağrıda site haritası yapısı yeniden oluşturulur. Son olarak özelliği, CachedDate
böyle bir değer varsa veri önbelleğinde depolanan tarih ve saat değerini döndürür. Bu özellik, site haritası verilerinin en son ne zaman önbelleğe alındığını belirlemek için bir sayfa geliştiricisi tarafından kullanılabilir.
7. Adım:NorthwindSiteMapProvider
Web uygulamamızın 6. Adımda oluşturulan site haritası sağlayıcısını kullanabilmesi NorthwindSiteMapProvider
için bunu bölümüne Web.config
kaydetmemiz <siteMap>
gerekir. Özellikle, içindeki öğesine Web.config
aşağıdaki işaretlemeyi <system.web>
ekleyin:
<siteMap defaultProvider="AspNetXmlSiteMapProvider">
<providers>
<add name="Northwind" type="NorthwindSiteMapProvider" />
</providers>
</siteMap>
Bu işaretleme iki işlem yapar: ilk olarak, yerleşikin AspNetXmlSiteMapProvider
varsayılan site haritası sağlayıcısı olduğunu gösterir; ikinci olarak, 6. Adımda oluşturulan özel site haritası sağlayıcısını Northwind adlı insan dostu bir adla kaydeder.
Not
Uygulama App_Code
klasöründe bulunan site haritası sağlayıcıları için özniteliğin type
değeri yalnızca sınıf adıdır. Alternatif olarak, özel site haritası sağlayıcısı, derlenmiş derlemenin web uygulamasının /Bin
dizinine yerleştirildiği ayrı bir Sınıf Kitaplığı projesinde oluşturulmuş olabilir. Bu durumda öznitelik type
değeri Ad Alanı olacaktır.ClassName, AssemblyName .
güncelleştirdikten Web.config
sonra, öğreticilerdeki herhangi bir sayfayı tarayıcıda görüntülemek için biraz zaman ayırın. Sol taraftaki gezinti arabiriminde hala içinde tanımlanan bölümlerin ve öğreticilerin gösterildiğini Web.sitemap
unutmayın. Bunun nedeni varsayılan sağlayıcı olarak ayrılmamızdır AspNetXmlSiteMapProvider
. kullanan NorthwindSiteMapProvider
bir gezinti kullanıcı arabirimi öğesi oluşturmak için Northwind site haritası sağlayıcısının kullanılması gerektiğini açıkça belirtmemiz gerekir. 8. Adımda bunu nasıl gerçekleştirebileceğimizi göreceğiz.
8. Adım: Özel Site Haritası Sağlayıcısını Kullanarak Site Haritası Bilgilerini Görüntüleme
özel site haritası sağlayıcısını oluşturup içinde Web.config
kaydettirdikten sonra klasördeki , ProductsByCategory.aspx
ve ProductDetails.aspx
sayfalarına gezinti denetimleri Default.aspx
eklemeye SiteMapProvider
hazırız. Başlangıç olarak sayfayı Default.aspx
açın ve SiteMapPath
Araç Kutusu'ndan Tasarım Aracı sürükleyin. SiteMapPath denetimi, Araç Kutusu'nun Gezinti bölümünde bulunur.
Şekil 16: 'a Default.aspx
Site Haritası Yolu ekleme (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Site HaritasıPath denetimi, site haritasındaki geçerli sayfanın konumunu gösteren bir içerik haritası görüntüler. Ana Sayfalar ve Site Gezintisi öğreticisinde ana sayfanın en üstüne bir Site Haritası Yolu ekledik.
Bu sayfayı bir tarayıcı üzerinden görüntülemek için biraz zaman ayırın. Şekil 16'da eklenen Site HaritasıYolu, varsayılan site haritası sağlayıcısını kullanarak verilerini konumundan Web.sitemap
çeker. Bu nedenle içerik haritası, tıpkı sağ üst köşedeki içerik haritasında olduğu gibi Site Haritası'nı Özelleştiren Giriş'i > gösterir.
Şekil 17: İçerik Haritası Varsayılan Site Haritası Sağlayıcısını Kullanır (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Şekil 16'da Site HaritasıPath'in eklenmesi için, 6. Adımda oluşturduğumuz özel site haritası sağlayıcısını SiteMapProvider
kullanın, özelliğini içinde Web.config
atadığımız NorthwindSiteMapProvider
ad olan Northwind olarak ayarlayın. Ne yazık ki, Tasarım Aracı varsayılan site haritası sağlayıcısını kullanmaya devam eder, ancak bu özellik değişikliğini yaptıktan sonra sayfayı bir tarayıcı üzerinden ziyaret ederseniz içerik haritasının artık özel site haritası sağlayıcısını kullandığını görürsünüz.
Şekil 18: İçerik Haritası Artık Özel Site Haritası Sağlayıcısını NorthwindSiteMapProvider
Kullanıyor (Tam boyutlu görüntüyü görüntülemek için tıklayın)
SiteMapPath denetimi, ve ProductDetails.aspx
sayfalarında daha işlevsel bir kullanıcı arabirimi ProductsByCategory.aspx
görüntüler. Her ikisinde de özelliğini Northwind olarak ayarlayarak SiteMapProvider
bu sayfalara bir Site Haritası Yolu ekleyin. İçecekler Default.aspx
için Ürünleri Görüntüle bağlantısına ve ardından Chai Tea için Ayrıntıları Görüntüle bağlantısına tıklayın. Şekil 19'da gösterildiği gibi içerik haritası geçerli site haritası bölümünü ( Chai Tea ) ve onun atalarını içerir: İçecekler ve Tüm Kategoriler .
Şekil 19: İçerik Haritası Artık Özel Site Haritası Sağlayıcısını NorthwindSiteMapProvider
Kullanıyor (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Menu ve TreeView denetimleri gibi SiteMapPath'e ek olarak diğer gezinti kullanıcı arabirimi öğeleri kullanılabilir. Default.aspx
Bu öğretici için indirilen , ProductsByCategory.aspx
ve ProductDetails.aspx
sayfaları, örneğin, tüm Menü denetimlerini içerir (bkz. Şekil 20). ASP.NET 2.0'daki gezinti denetimlerine ve site haritası sistemine daha ayrıntılı bir bakış için ASP.NET 2.0 Hızlı Başlangıçları'nın Gelişmiş Site Gezinti Özellikleri'nin ASP.NET ve Site Gezinti Denetimlerini Kullanma bölümüne bakın.
Şekil 20: Menü Denetimi Kategorilerin ve Ürünlerin Her Birini Listeler (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Bu öğreticide daha önce belirtildiği gibi, site haritası yapısına sınıf üzerinden SiteMap
program aracılığıyla erişilebilir. Aşağıdaki kod varsayılan sağlayıcının kökünü SiteMapNode
döndürür:
SiteMapNode root = SiteMap.RootNode;
AspNetXmlSiteMapProvider
, uygulamamız için varsayılan sağlayıcı olduğundan, yukarıdaki kod içinde Web.sitemap
tanımlanan kök düğümü döndürür. Varsayılan dışında bir site haritası sağlayıcısına başvurmak için aşağıdaki gibi sınıf s Providers
özelliğini kullanınSiteMap
:
SiteMapNode root = SiteMap.Providers["name"].RootNode;
Burada ad , özel site haritası sağlayıcısının adıdır (Web uygulamamız için Northwind).
Site haritası sağlayıcısına özgü bir üyeye erişmek için öğesini kullanarak SiteMap.Providers["name"]
sağlayıcı örneğini alın ve uygun türe yayınlayın. Örneğin, s CachedDate
özelliğini bir ASP.NET sayfasında görüntülemek NorthwindSiteMapProvider
için aşağıdaki kodu kullanın:
NorthwindSiteMapProvider customProvider =
SiteMap.Providers["Northwind"] as NorthwindSiteMapProvider;
if (customProvider != null)
{
DateTime? lastCachedDate = customProvider.CachedDate;
if (lastCachedDate != null)
LabelID.Text = "Site map cached on: " + lastCachedDate.Value.ToString();
else
LabelID.Text = "The site map is being reconstructed!";
}
Not
SQL önbellek bağımlılığı özelliğini test etmeye dikkat edin. , ProductsByCategory.aspx
ve sayfalarını ziyaret ettikten Default.aspx
sonra Düzenleme, Ekleme ve ProductDetails.aspx
Silme bölümündeki öğreticilerden birine gidin ve bir kategorinin veya ürünün adını düzenleyin. Ardından klasördeki SiteMapProvider
sayfalardan birine dönün. Temel alınan veritabanındaki değişikliği not etmek için yoklama mekanizması için yeterli süre geçtiğini varsayarsak, site haritasının yeni ürün veya kategori adını gösterecek şekilde güncelleştirilmesi gerekir.
Özet
ASP.NET 2.0 sn site haritası özellikleri bir SiteMap
sınıf, bir dizi yerleşik gezinti Web denetimi ve site haritası bilgilerinin bir XML dosyasında kalıcı olmasını bekleyen bir varsayılan site haritası sağlayıcısı içerir. Veritabanı, uygulama mimarisi veya uzak bir Web hizmeti gibi başka bir kaynaktan site haritası bilgilerini kullanmak için özel bir site haritası sağlayıcısı oluşturmamız gerekir. Bu, doğrudan veya dolaylı olarak sınıfından SiteMapProvider
türetilen bir sınıf oluşturmayı içerir.
Bu öğreticide, uygulama mimarisinden kaynaklanan ürün ve kategori bilgileri üzerinde site haritasını temel alan özel bir site haritası sağlayıcısının nasıl oluşturulacağını gördük. Sağlayıcımız sınıfını StaticSiteMapProvider
genişletti ve verileri alan, site haritası hiyerarşisini oluşturan ve sonuçta elde edilen yapıyı sınıf düzeyinde bir değişkende önbelleğe alan bir yöntem oluşturmayı BuildSiteMap
gerektiriyordu. Temel alınan Categories
veya Products
veriler değiştirildiğinde önbelleğe alınan yapıyı geçersiz kılma amacıyla bir geri çağırma işleviyle sql önbellek bağımlılığı kullandık.
Mutlu Programlama!
Daha Fazla Bilgi
Bu öğreticide ele alınan konular hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:
- Site Haritalarını SQL Server veBeklediğiniz SQL Site Haritası Sağlayıcısında Depolama
- Sağlayıcı Araç Seti
- ASP.NET 2.0'ın Gelişmiş Site Gezinti Özellikleri
Yazar hakkında
Yedi ASP/ASP.NET kitabının yazarı ve 4GuysFromRolla.com kurucusu Scott Mitchell, 1998'den beri Microsoft Web teknolojileriyle çalışmaktadır. Scott bağımsız bir danışman, eğitmen ve yazar olarak çalışmaktadır. Son kitabı Sams Teach Yourself ASP.NET 24 Hours 2.0'dır. Adresine adresinden veya adresinden ulaşabileceğiniz http://ScottOnWriting.NETblogu aracılığıyla ulaşabilirsinizmitchell@4GuysFromRolla.com.
Özel Teşekkürler
Bu öğretici serisi birçok yararlı gözden geçiren tarafından gözden geçirildi. Bu öğreticinin baş gözden geçirenleri Dave Gardner, Zack Jones, Teresa Murphy ve Bernadette Leigh oldu. Yaklaşan MSDN makalelerimi gözden geçirmek istiyor musunuz? Öyleyse, bana adresinden bir satır mitchell@4GuysFromRolla.combırakın.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin