<div id="divHomepageBestSellers">
</div>
$(document).ready(function () { // 通过ajax来实现 以上html代码的显示
$.ajax({ cache: false,
type: "POST",
url: "@(Url.RouteUrl("HomepageBestSellersJson"))",//这个路由已定义
data: { "productThumbPictureSize": 75 },
success: function (data) {
$("#divHomepageBestSellers").html(data.html);
},
error:function (xhr, ajaxOptions, thrownError){ }
});
});
通过ajax来实现调用HomepageBestSellersJson的action,下面我们来看看它的代码
[HttpPost]
public ActionResult HomepageBestSellersJson(int? productThumbPictureSize, int? orderBy, int? categoryId)
{
if (!_catalogSettings.ShowBestsellersOnHomepage||_ catalogSettings.NumberOfBestsellersOnHomepage== 0)
return Json(new { html = "" });//这一步只是显示的判断,不比理会
var model = GetHomePageBestsellersModel(productThumbPictureSize, orderBy,categoryId);//这是获取model,
return Json(new { html = this.RenderPartialViewToString("HomepageBestSellers", model), });
}
接下来是我讲的重点了,是如何实现这个的 return Json(new { html = this.RenderPartialViewToString("HomepageBestSellers", model), });
先来看看RenderPartialViewToString这个方法,从下面代码可以看到他是Controller的拓展方法:
public static class ContollerExtensions
{
public static string RenderPartialViewToString(this Controller controller, string viewName, object model)
{ //Original source code: http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/
if (string.IsNullOrEmpty(viewName))
viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
controller.ViewData.Model = model;//传入MODEL数据
using (var sw = new StringWriter())
{
ViewEngineResult viewResult = System.Web.Mvc.ViewEngines.
Engines.FindPartialView(controller.ControllerContext, viewName);//这一步是找到VIEW
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View,
controller.ViewData, controller.TempData, sw);//这步是实现把controller中的Model的数据传入VIEW中,
//并通过viewResult.View.Render生成string代码,这样就完成开始的ajax的调用和实现
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
}
先来看看System.Web.Mvc.ViewEngines.Engines.FindPartialView具体实现和该方法所属类(ThemeableVirtualPathProviderViewEngine )的继承关系,
public abstract class ThemeableVirtualPathProviderViewEngine : VirtualPathProviderViewEngine
{
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
var mobileDeviceHelper = EngineContext.Current.Resolve<IMobileDeviceHelper>();
bool useMobileDevice = mobileDeviceHelper.IsMobileDevice(controllerContext.HttpContext)
&& mobileDeviceHelper.MobileDevicesSupported()
&& !mobileDeviceHelper.CustomerDontUseMobileVersion();
string overrideViewName = useMobileDevice ? string.Format("{0}.{1}", partialViewName, _mobileViewModifier) : partialViewName;
ViewEngineResult result = FindThemeablePartialView(controllerContext, overrideViewName, useCache, useMobileDevice);
// If we're looking for a Mobile view and couldn't find it try again without modifying the viewname
if (useMobileDevice && (result == null || result.View == null))
result = FindThemeablePartialView(controllerContext, partialViewName, useCache, false);
return result;
}
protected virtual ViewEngineResult FindThemeablePartialView(ControllerContext controllerContext,string partialViewName,
bool useCache, bool mobile)
{
string[] strArray;
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(partialViewName))
{
throw new ArgumentException("Partial view name cannot be null or empty.", "partialViewName");
}
var theme = GetCurrentTheme(mobile);
string requiredString = controllerContext.RouteData.GetRequiredString("controller");
string str2 = this.GetPath(controllerContext, this.PartialViewLocationFormats,
this.AreaPartialViewLocationFormats, "PartialViewLocationFormats",
partialViewName, requiredString, theme, "Partial", useCache,
mobile, out strArray);
if (string.IsNullOrEmpty(str2))
{
return new ViewEngineResult(strArray);
}
return new ViewEngineResult(this.CreatePartialView(controllerContext, str2), this);
}
protected virtual string GetPath(ControllerContext controllerContext, string[] locations,
string[] areaLocations, string locationsPropertyName,
string name, string controllerName, string theme, string cacheKeyPrefix,
bool useCache, bool mobile, out string[] searchedLocations)
{
searchedLocations = _emptyLocations;
if (string.IsNullOrEmpty(name))
{
return string.Empty;
}
string areaName = GetAreaName(controllerContext.RouteData);//little hack to get nop's admin area to be in /Administration/
//instead of /Nop/Admin/ or Areas/Admin/
if (!string.IsNullOrEmpty(areaName) && areaName.Equals("admin", StringComparison.InvariantCultureIgnoreCase))
{ //admin area does not support mobile devices
if (mobile)
{
searchedLocations = new string[0];
return string.Empty;
}
var newLocations = areaLocations.ToList();
newLocations.Insert(0, "~/Administration/Views/{1}/{0}.cshtml");
newLocations.Insert(0, "~/Administration/Views/{1}/{0}.vbhtml");
newLocations.Insert(0, "~/Administration/Views/Shared/{0}.cshtml");
newLocations.Insert(0, "~/Administration/Views/Shared/{0}.vbhtml");
areaLocations = newLocations.ToArray();
}
bool flag = !string.IsNullOrEmpty(areaName);
List<ViewLocation> viewLocations = GetViewLocations(locations, flag ? areaLocations : null);
if (viewLocations.Count == 0)
{
throw new InvalidOperationException(
string.Format(CultureInfo.CurrentCulture,
"Properties cannot be null or empty.",
new object[] { locationsPropertyName }));
}
bool flag2 = IsSpecificPath(name);
string key = this.CreateCacheKey(cacheKeyPrefix, name, flag2 ? string.Empty : controllerName, areaName, theme);
if (useCache)
{
var cached = this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key);
if (cached != null)
{
return cached;
}
}
if (!flag2)
{
return this.GetPathFromGeneralName(controllerContext, viewLocations, name,
controllerName, areaName, theme, key, ref searchedLocations);
}
return this.GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations);
}
}
还有一些具体的方法没有给出,希望大家去看看nop的源码会有很大的收获的,也许我讲的不怎么清洗,但是我希望大家能够理解大致的流程,这功能对我们来说是很有用的,阿门!