- همیشه در دسترس است و نیاز به ذخیرهسازی ندارد
- افزونههای کلیپ کردن مطلب هایتلایت شده و ارسال مستقیم اون از مرورگر به واننت
- ایجاد صفحات همراه با زیرشاخه درست کردن به نحوی که از نظر منطقی و زیبایی عالی عمل میکنه.
// <![CDATA[ (function ($) { $.bootstrapModalConfirm = function (options) { var defaults = { caption: 'تائید عملیات', body: 'آیا عملیات درخواستی اجرا شود؟', onConfirm: null, confirmText: 'تائید', closeText: 'انصراف' }; var options = $.extend(defaults, options); var confirmContainer = "#confirmContainer"; var html = '<div class="modal hide fade" id="confirmContainer">' + '<div class="modal-header">' + '<a class="close" data-dismiss="modal">×</a>' + '<h5>' + options.caption + '</h5></div>' + '<div class="modal-body">' + options.body + '</div>' + '<div class="modal-footer">' + '<a href="#" class="btn btn-success" id="confirmBtn">' + options.confirmText + '</a>' + '<a href="#" class="btn" data-dismiss="modal">' + options.closeText + '</a></div></div>'; $(confirmContainer).remove(); $(html).appendTo('body'); $(confirmContainer).modal('show'); $('#confirmBtn', confirmContainer).click(function () { if (options.onConfirm) options.onConfirm(); $(confirmContainer).modal('hide'); }); }; })(jQuery); // ]]>
@{ ViewBag.Title = "Index"; } <h2> Index</h2> <a href="#" class="btn btn-danger" id="deleteBtn">حذف رکورد</a> @section JavaScript { <script type="text/javascript"> $(function () { $("#deleteBtn").click(function (e) { e.preventDefault(); //میخواهیم لینک به صورت معمول عمل نکند $.bootstrapModalConfirm({ caption: 'تائید عملیات', body: 'آیا عملیات درخواستی اجرا شود؟', onConfirm: function () { alert('در حال انجام عملیات'); }, confirmText: 'تائید', closeText: 'انصراف' }); }); }); </script> }
body { margin: 0;"Helvetica Neue", Helvetica, Arial, sans-serif; color: #333333; background-color: #ffffff; }
<div class="row-fluid"> <div class="span12"> <h1> سرتیتر 1 </h1> <h2> سرتیتر 2 </h2> <h3> سرتیتر 3 </h3> <h4> سرتیتر 4 </h4> <h5> سرتیتر 5 </h5> <h6> سرتیتر 6 </h6> </div> </div> |
<div class="row-fluid"> <div class="span12"> <p class="lead"> تیتر</p> <p> متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن </p> <small>اندازه کوچک</small> <strong>متن ضخیم</strong> <em>متن ایتالیک</em> </div> </div>
<div class="row-fluid"> <div class="span12"> <p class="muted"> متن غیرفعال</p> <p class="text-warning"> نمایش اخطار به کاربر</p> <p class="text-error"> نمایش خطا به کاربر</p> <p class="text-info"> نمایش اطلاعات به کاربر</p> <p class="text-success"> نمایش موفقیت آمیز بودن عملیات</p> </div> </div> |
<div class="row-fluid"> <div class="span12"> <p> My <abbr title="منظور واحد پردازش مرکزی است"> CPU</abbr> has N Cores. </p> </div> </div> |
<div class="row-fluid"> <div class="span12"> <address> وحید نصیری <br /> ایران، تهران <br /> <abbr title="Phone"> P:</abbr> 12345678 <br /> <abbr title="Cell"> C:</abbr> 12345678 </address> </div> </div> |
<div class="row-fluid"> <div class="span12"> <blockquote> <p> جهت نمایش نقل قول </p> <small><cite title="کاربر شماره 2">از شخصی</cite> </small> </blockquote> </div> </div> |
<div class="row-fluid"> <div class="span6"> <ul class="unstyled"> <li>یک </li> <li>دو </li> <li>سه </li> </ul> </div> <div class="span6"> <ol> <li>یک </li> <li>دو </li> <li>سه </li> </ol> </div> </div> |
<div class="row-fluid"> <div class="span12"> <dl class="dl-horizontal"> <dt>عنوان</dt> <dd> توضیحات بلند در اینجا</dd> </dl> </div> </div> |
<div class="row-fluid"> <div class="span6"> <code>inline code</code> </div> <div class="span6"> <pre class="pre-scrollable"> code code code </pre> </div> </div> |
<div class="container-fluid"> <div class="row-fluid"> <div class="span12"> <table class="table table-striped table-hover table-bordered table-condensed"> <caption> عنوانی خاص در اینجا</caption> <thead> <tr> <th> ستون یک </th> <th> ستون دو </th> <th> ستون سه </th> </tr> </thead> <tbody> <tr class="error"> <td> 1 متن یک </td> <td> 1 متن دو </td> <td> 1 متن سه </td> </tr> <tr> <td> 2 متن یک </td> <td> 2 متن دو </td> <td> 2 متن سه </td> </tr> <tr> <td> 3 متن یک </td> <td> 3 متن دو </td> <td> 3 متن سه </td> </tr> </tbody> </table> </div> </div> </div>
<div class="container-fluid"> <div class="row-fluid"> <div class="span12"> <form action="/signup" method="post"> <fieldset> <legend>ثبت نام</legend> <label> ایمیل:</label> <input name="email" type="text" /> <label> نام:</label> <input name="name" type="text" /> </fieldset> </form> </div> </div> </div> |
<label class="checkbox"> <input type="checkbox" name="isMale" /> مذکر</label>
<div> <label class="radio inline"> <input type="radio" name="isMale" /> مذکر</label> <label class="radio inline"> <input type="radio" name="isFemale" /> مؤنث</label> </div> |
4) تعیین اندازه فیلدها
<form class="search-form"> <fieldset> <legend>جستجو</legend> <input type="search" class="search-query" /> <button type="submit" class="btn" >بیاب</button> </fieldset> </form> |
<form class="form-horizontal" action="/signup" method="post"> <fieldset> <legend>ثبت نام</legend> <div class="control-group"> <label class="control-label"> ایمیل:</label> <div class="controls"> <input name="email" type="text" /> </div> </div> <div class="control-group"> <label class="control-label"> نام:</label> <div class="controls"> <input name="name" type="text" /> </div> </div> <div class="control-group"> <div class="controls"> <label class="radio inline"> <input type="radio" name="isMale" /> مذکر</label> <label class="radio inline"> <input type="radio" name="isFemale" /> مؤنث</label> </div> </div> </fieldset> </form> |
<div class="control-group error"> <label class="control-label"> ایمیل:</label> <div class="controls"> <input name="email" type="text" /> <span class="help-block">لطفا ایمیل را با فرمت صحیحی وارد نمائید</span> </div> </div> |
<div class="input-prepend input-append"> <span dir="ltr" class="add-on">.00</span> <input dir="ltr" type="text" /> <span class="add-on">ریال</span> </div> |
<div class="container-fluid"> <div class="row-fluid"> <div class="span12"> <table class="table table-striped table-hover table-bordered table-condensed"> <thead> <tr> <th> دکمه </th> <th> لینک </th> <th> کلاس بکار گرفته شده </th> </tr> </thead> <tbody> <tr> <td> <button class="btn"> default</button> </td> <td> <a href="#" class="btn">default</a> </td> <td> <code>btn</code> </td> </tr> <tr> <td> <button class="btn btn-primary"> primary</button> </td> <td> <a href="#" class="btn btn-primary">primary</a> </td> <td> <code>btn btn-primary</code> </td> </tr> <tr> <td> <button class="btn btn-info"> info</button> </td> <td> <a href="#" class="btn btn-info">info</a> </td> <td> <code>btn btn-info</code> </td> </tr> <tr> <td> <button class="btn btn-success"> success</button> </td> <td> <a href="#" class="btn btn-success">success</a> </td> <td> <code>btn btn-success</code> </td> </tr> <tr> <td> <button class="btn btn-warning"> warning</button> </td> <td> <a href="#" class="btn btn-warning">warning</a> </td> <td> <code>btn btn-warning</code> </td> </tr> <tr> <td> <button class="btn btn-danger"> danger</button> </td> <td> <a href="#" class="btn btn-danger">danger</a> </td> <td> <code>btn btn-danger</code> </td> </tr> <tr> <td> <button class="btn btn-inverse"> inverse</button> </td> <td> <a href="#" class="btn btn-inverse">inverse</a> </td> <td> <code>btn btn-inverse</code> </td> </tr> <tr> <td> <button class="btn btn-link"> link</button> </td> <td> <a href="#" class="btn btn-link">link</a> </td> <td> <code>btn btn-link</code> </td> </tr> <tr> <td> <button class="btn btn-primary btn-large"> large</button> </td> <td> <a href="#" class="btn btn-primary btn-large">large</a> </td> <td> <code>btn btn-primary btn-large</code> </td> </tr> <tr> <td> <button class="btn btn-primary btn-small"> small</button> </td> <td> <a href="#" class="btn btn-primary btn-small">small</a> </td> <td> <code>btn btn-primary btn-small</code> </td> </tr> <tr> <td> <button class="btn btn-primary btn-mini"> mini</button> </td> <td> <a href="#" class="btn btn-primary btn-mini">mini</a> </td> <td> <code>btn btn-primary btn-mini</code> </td> </tr> <tr> <td> <button class="btn btn-primary btn-block"> block</button> </td> <td> <a href="#" class="btn btn-primary btn-block">block</a> </td> <td> <code>btn btn-primary btn-block</code> </td> </tr> <tr> <td> <button class="btn btn-primary disabled"> disabled</button> </td> <td> <a href="#" class="btn btn-primary disabled">disabled</a> </td> <td> <code>btn btn-primary disabled</code> </td> </tr> </tbody> </table> </div> </div> </div>
<i class="icon-music"></i>icon-music
<i class="icon-music icon-white"></i>icon-music
<button class="btn"> <i class="icon-music"></i>دکمه</button>
<div class="input-prepend"> <span class="add-on"><i class="icon-envelope"></i></span> <input type="email" dir="ltr" /> </div> |
namespace jQueryMvcSample02.Models { public class BlogPost { public int Id { set; get; } public string Title { set; get; } public string Body { set; get; } } }
using System.Collections.Generic; using System.Linq; using jQueryMvcSample02.Models; namespace jQueryMvcSample02.DataSource { public static class BlogPostDataSource { private static IList<BlogPost> _cachedItems; /// <summary> /// با توجه به استاتیک بودن سازنده کلاس، تهیه کش، پیش از سایر فراخوانیها صورت خواهد گرفت /// باید دقت داشت که این فقط یک مثال است و چنین کشی به معنای /// تهیه یک لیست برای تمام کاربران سایت است /// </summary> static BlogPostDataSource() { _cachedItems = createBlogPostsInMemoryDataSource(); } /// <summary> /// هدف صرفا تهیه یک منبع داده آزمایشی ساده تشکیل شده در حافظه است /// </summary> private static IList<BlogPost> createBlogPostsInMemoryDataSource() { var results = new List<BlogPost>(); for (int i = 1; i < 30; i++) { results.Add(new BlogPost { Id = i, Title = "عنوان " + i, Body = "متن ... متن ... متن " + i }); } return results; } /// <summary> /// پارامترهای شماره صفحه و تعداد رکورد به ازای یک صفحه برای صفحه بندی نیاز هستند /// شماره صفحه از یک شروع میشود /// </summary> public static IList<BlogPost> GetLatestBlogPosts(int pageNumber, int recordsPerPage = 4) { var skipRecords = pageNumber * recordsPerPage; return _cachedItems .OrderByDescending(x => x.Id) .Skip(skipRecords) .Take(recordsPerPage) .ToList(); } } }
using System.Linq; using System.Web.Mvc; using System.Web.UI; using jQueryMvcSample02.DataSource; using jQueryMvcSample02.Security; namespace jQueryMvcSample02.Controllers { public class HomeController : Controller { [HttpGet] public ActionResult Index() { //آغاز کار با صفحه صفر است var list = BlogPostDataSource.GetLatestBlogPosts(pageNumber: 0); return View(list); //نمایش ابتدایی صفحه } [HttpPost] [AjaxOnly] [OutputCache(Location = OutputCacheLocation.None, NoStore = true)] public virtual ActionResult PagedIndex(int? page) { var pageNumber = page ?? 0; var list = BlogPostDataSource.GetLatestBlogPosts(pageNumber); if (list == null || !list.Any()) return Content("no-more-info"); //این شرط ما است برای نمایش عدم یافتن رکوردها return PartialView("_ItemsList", list); } [HttpGet] public ActionResult Post(int? id) { if (id == null) return Redirect("/"); //todo: show the content here return Content("Post " + id.Value); } } }
@model IList<jQueryMvcSample02.Models.BlogPost> <ul> @foreach (var item in Model) { <li> <h5> @Html.ActionLink(linkText: item.Title, actionName: "Post", controllerName: "Home", routeValues: new { id = item.Id }, htmlAttributes: null) </h5> @item.Body </li> } </ul>
@model IList<jQueryMvcSample02.Models.BlogPost> @{ ViewBag.Title = "Index"; var loadInfoUrl = Url.Action(actionName: "PagedIndex", controllerName: "Home"); } <h2> اسکرول نامحدود</h2> @{ Html.RenderPartial("_ItemsList", Model); } <div id="MoreInfoDiv"> </div> <div align="center" style="margin-bottom: 9px;"> <span id="moreInfoButton" style="width: 90%;" class="btn btn-info">بیشتر</span> </div> <div id="ProgressDiv" align="center" style="display: none"> <br /> <img src="@Url.Content("~/Content/images/loadingAnimation.gif")" alt="loading..." /> </div> @section JavaScript { <script type="text/javascript"> $(document).ready(function () { $("#moreInfoButton").InfiniteScroll({ moreInfoDiv: '#MoreInfoDiv', progressDiv: '#ProgressDiv', loadInfoUrl: '@loadInfoUrl', loginUrl: '/login', errorHandler: function () { alert('خطایی رخ داده است'); }, completeHandler: function () { // اگر قرار است روی اطلاعات نمایش داده شده پردازش ثانوی صورت گیرد }, noMoreInfoHandler: function () { alert('اطلاعات بیشتری یافت نشد'); } }); }); </script> }
// <![CDATA[ (function ($) { $.fn.InfiniteScroll = function (options) { var defaults = { moreInfoDiv: '#MoreInfoDiv', progressDiv: '#Progress', loadInfoUrl: '/', loginUrl: '/login', errorHandler: null, completeHandler: null, noMoreInfoHandler: null }; var options = $.extend(defaults, options); var showProgress = function () { $(options.progressDiv).css("display", "block"); } var hideProgress = function () { $(options.progressDiv).css("display", "none"); } return this.each(function () { var moreInfoButton = $(this); var page = 1; $(moreInfoButton).click(function (event) { showProgress(); $.ajax({ type: "POST", url: options.loadInfoUrl, data: JSON.stringify({ page: page }), contentType: "application/json; charset=utf-8", dataType: "json", complete: function (xhr, status) { var data = xhr.responseText; if (xhr.status == 403) { window.location = options.loginUrl; } else if (status === 'error' || !data) { if (options.errorHandler) options.errorHandler(this); } else { if (data == "no-more-info") { if (options.noMoreInfoHandler) options.noMoreInfoHandler(this); } else { var $boxes = $(data); $(options.moreInfoDiv).append($boxes); } page++; } hideProgress(); if (options.completeHandler) options.completeHandler(this); } }); }); }); }; })(jQuery); // ]]>
نام این جدول را با درنظر گرفتن شرایط موجود میتوان Resources گذاشت.
ستون Name برای ذخیره نام منبع درنظر گرفته شده است. این نام برابر نام منابع درخواستی در سیستم مدیریت منابع ASP.NET است که درواقع برابر همان نام فایل منبع اما بدون پسوند resx. است.
ستون Key برای نگهداری کلید ورودی منبع استفاده میشود که دقیقا برابر همان مقداری است که درون فایلهای resx. ذخیره میشود.
ستون Culture برای ذخیره کالچر ورودی منبع به کار میرود. این مقدار میتواند برای کالچر پیشفرض برنامه برابر رشته خالی باشد.
ستون Value نیز برای نگهداری مقدار ورودی منبع استفاده میشود.
برای ستون Id میتوان از GUID نیز استفاده کرد. در اینجا برای راحتی کار از نوع داده bigint و خاصیت Identity برای تولید خودکار آن در Sql Server استفاده شده است.
نکته: برای امنیت بیشتر میتوان یک Unique Constraint بر روی سه فیلد Name و Key و Culture اعمال کرد.
برای نمونه به تصویر زیر که ذخیره تعدای ورودی منبع را درون جدول Resources نمایش میدهد دقت کنید:
اصلاح کلاس DbResourceProviderFactory
برای ذخیره منابع محلی، جهت اطمینان از یکسان بودن نام منبع، متد مربوطه در کلاس DbResourceProviderFactory باید بهصورت زیر تغییر کند:
public override IResourceProvider CreateLocalResourceProvider(string virtualPath) { if (!string.IsNullOrEmpty(virtualPath)) { virtualPath = virtualPath.Remove(0, virtualPath.IndexOf('/') + 1); // removes everything from start to the first '/' } return new LocalDbResourceProvider(virtualPath); }
ارتباط با دیتابیس
خوشبختانه برای تبادل اطلاعات با جدول بالا امروزه راههای زیادی وجود دارد. برای پیادهسازی آن مثلا میتوان از یک اینترفیس استفاده کرد. سپس با استفاده از سازوکارهای موجود مثلا بهکارگیری IoC، نمونه مناسبی از پیادهسازی اینترفیس مذبور را در اختیار برنامه قرار داد.
اما برای جلوگیری از پیچیدگی بیش از حد و دور شدن از مبحث اصلی، برای پیادهسازی فعلی از EF Code First به صورت مستقیم در پروژه استفاده شده است که سری آموزشی کاملی از آن در همین سایت وجود دارد.
پس از پیادهسازی کلاسهای مرتبط برای استفاده از EF Code First، از کلاس ResourceData که در بخش اول نیز نشان داده شده بود، برای کپسوله کردن ارتباط با دادهها استفاده میشود که نمونهای ابتدایی از آن در زیر آورده شده است:
using System.Collections.Generic; using System.Linq; using DbResourceProvider.Models; namespace DbResourceProvider.Data { public class ResourceData { private readonly string _resourceName; public ResourceData(string resourceName) { _resourceName = resourceName; } public Resource GetResource(string resourceKey, string culture) { using (var data = new TestContext()) { return data.Resources.SingleOrDefault(r => r.Name == _resourceName && r.Key == resourceKey && r.Culture == culture); } } public List<Resource> GetResources(string culture) { using (var data = new TestContext()) { return data.Resources.Where(r => r.Name == _resourceName && r.Culture == culture).ToList(); } } } }
using System.Collections.Generic; using System.Globalization; using DbResourceProvider.Data; namespace DbResourceProvider { public class DbResourceManager { private readonly string _resourceName; private readonly Dictionary<string, Dictionary<string, object>> _resourceCacheByCulture; public DbResourceManager(string resourceName) { _resourceName = resourceName; _resourceCacheByCulture = new Dictionary<string, Dictionary<string, object>>(); } public object GetObject(string resourceKey, CultureInfo culture) { return GetCachedObject(resourceKey, culture.Name); } private object GetCachedObject(string resourceKey, string cultureName) { if (!_resourceCacheByCulture.ContainsKey(cultureName)) _resourceCacheByCulture.Add(cultureName, new Dictionary<string, object>()); var cachedResource = _resourceCacheByCulture[cultureName]; lock (this) { if (!cachedResource.ContainsKey(resourceKey)) { var data = new ResourceData(_resourceName); var dbResource = data.GetResource(resourceKey, cultureName); if (dbResource == null) return null; var cachedResources = _resourceCacheByCulture[cultureName]; cachedResources.Add(dbResource.Key, dbResource.Value); } } return cachedResource[resourceKey]; } } }
private object GetCachedObject(string resourceKey, string cultureName) { lock (this) { if (!_resourceCacheByCulture.ContainsKey(cultureName)) { _resourceCacheByCulture.Add(cultureName, new Dictionary<string, object>()); var cachedResources = _resourceCacheByCulture[cultureName]; var data = new ResourceData(_resourceName); var dbResources = data.GetResources(cultureName); foreach (var dbResource in dbResources) { cachedResources.Add(dbResource.Key, dbResource.Value); } } } var cachedResource = _resourceCacheByCulture[cultureName]; return !cachedResource.ContainsKey(resourceKey) ? null : cachedResource[resourceKey]; }
using System.Collections; using System.Collections.Generic; using System.Globalization; namespace DbResourceProvider { public class CultureFallbackProvider : IEnumerable<CultureInfo> { private readonly CultureInfo _startingCulture; private readonly CultureInfo _neutralCulture; private readonly bool _tryParentCulture; public CultureFallbackProvider(CultureInfo startingCulture = null, CultureInfo neutralCulture = null, bool tryParentCulture = true) { _startingCulture = startingCulture ?? CultureInfo.CurrentUICulture; _neutralCulture = neutralCulture; _tryParentCulture = tryParentCulture; } #region Implementation of IEnumerable<CultureInfo> public IEnumerator<CultureInfo> GetEnumerator() { var reachedNeutralCulture = false; var currentCulture = _startingCulture; do { if (_neutralCulture != null && currentCulture.Name == _neutralCulture.Name) { yield return CultureInfo.InvariantCulture; reachedNeutralCulture = true; break; } yield return currentCulture; currentCulture = currentCulture.Parent; } while (_tryParentCulture && !HasInvariantCultureName(currentCulture)); if (!_tryParentCulture || HasInvariantCultureName(_startingCulture) || reachedNeutralCulture) yield break; yield return CultureInfo.InvariantCulture; } #endregion #region Implementation of IEnumerable IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion private bool HasInvariantCultureName(CultureInfo culture) { return culture.Name == CultureInfo.InvariantCulture.Name; } } }
public object GetObject(string resourceKey, CultureInfo culture) { foreach (var currentCulture in new CultureFallbackProvider(culture)) { var value = GetCachedObject(resourceKey, currentCulture.Name); if (value != null) return value; } throw new KeyNotFoundException("The specified 'resourceKey' not found."); }
ابتدا تنظیمات موردنیاز فایل کانفیگ را که در قسمت قبل نشان داده شد، در برنامه خود اعمال کنید.
دادههای نمونه نشان داده شده در ابتدای این مطلب را درنظر بگیرید. حال اگر در یک برنامه وب اپلیکیشن، صفحه Default.aspx در ریشه سایت حاوی دو کنترل زیر باشد:
<asp:Label ID="Label1" runat="server" meta:resourcekey="Label1" /> <asp:Label ID="Label2" runat="server" meta:resourcekey="Label2" />
سپس تغییر زیر را در فایل web.config اعمال کنید تا کالچر UI سایت به fa تغییر یابد (به بخش "uiCulture="fa دقت کنید):
<globalization uiCulture="fa" resourceProviderFactoryType = "DbResourceProvider.DbResourceProviderFactory, DbResourceProvider" />
میبینید که با توجه به عدم وجود مقداری برای Label2.Text برای کالچر fa، عملیات fallback اتفاق افتاده است.
کار تولید یک پرووایدر منابع سفارشی دیتابیسی به اتمام رسید. تا اینجا اصول کلی تولید یک پرووایدر سفارشی شرح داده شد. بدین ترتیب میتوان برای هر حالت خاص دیگری نیز پرووایدرهای سفارشی مخصوص ساخت تا مدیریت منابع به آسانی تحت کنترل برنامه نویس قرار گیرد.
اما نکتهای را که باید به آن توجه کنید این است که در پیادهسازیهای نشان داده شده با توجه به نحوه کششدن مقادیر ورودیها، اگر این مقادیر در دیتابیس تغییر کنند، تا زمانیکه سایت ریست نشود این تغییرات در برنامه اعمال نخواهد شد. زیرا همانطور که اشاره شد، مدیریت نمونههای تولیدشده از پرووایدرهای منابع برای هر منبع درخواستی درنهایت برعهده ASP.NET است. بنابراین باید مکانیزمی پیاده شود تا کلاس DbResourceManager از بهروزرسانی ورودیهای کششده اطلاع یابد تا آنها را ریفرش کند.
در ادامه درباره روشهای مختلف نحوه پیادهسازی قابلیت بهروزرسانی ورودیهای منابع در زمان اجرا با استفاده از پرووایدرهای منابع سفارشی بحث خواهد شد. همچنین راهحلهای مختلف استفاده از این پرووایدرهای سفارشی در جاهای مختلف پروژههای MVC شرح داده میشود.
البته مباحث پیشرفتهتری چون تزریق وابستگی برای پیادهسازی لایه ارتباط با دیتابیس در بیرون و یا تولید یک Factory برای تزریق کامل پرووایدر منابع از بیرون نیز جای بحث و بررسی دارد.
منابع
http://msdn.microsoft.com/en-us/library/aa905797.aspx
http://msdn.microsoft.com/en-us/library/system.web.compilation.resourceproviderfactory.aspx
http://www.dotnetframework.org/default.aspx/.../ResourceFallbackManager@cs
http://www.codeproject.com/Articles/14190/ASP-NET-2-0-Custom-SQL-Server-ResourceProvider
function myfunc(){ $('#test')....; }
window.onload = myfunc;
window.addEventListener('load', myfunc1, false); window.addEventListener('load', myfunc2, false); ...