【发布时间】:2014-02-25 00:59:44
【问题描述】:
我正在尝试从用 ASP.Net Web 表单编写的 CMS 缓慢迁移到 ASP.Net MVC。为此,我需要将 Web 部件(自定义控件)的功能替换为部分视图的功能。 CMS 页面包含许多 Web 部件,每个部件最终都应从 MVC 局部视图呈现一些 html。我还需要一种方法来传递每个 Web 部件中设置的参数,并基于这些来构造局部视图。整个目的是将业务逻辑与表示分离,以消除对 CMS 本身的依赖。在此过程中,所有 Web 部件应该仍然可以工作。 您对实现这一目标的有效方法有任何想法或建议吗?
这是我的出发点。我正在尝试将 MVC 部分视图检索为 ASP.Net 管道之外的字符串。为此,我需要使用 HttpContext。由于我没有这个上下文(我只想使用通过某些接口传递的最少属性),我试图创建一个假的。
public class TestController : Controller, ICmsTranslator
{
public ActionResult Index()
{
return View();
}
public string RenderAsString(IHttpRequest request, IContext context)
{
return RenderRazorViewToString("~/Views/Shared/_TestPartialView.cshtml", new TestModels(), request, context);
}
public string RenderRazorViewToString(string viewName, object model, IHttpRequest request, IContext context)
{
ViewData.Model = model;
using (var sw = new StringWriter())
{
// create a fake HttpContext
var fakeRouteData = new RouteData();
if (!fakeRouteData.Values.ContainsKey("controller") && !fakeRouteData.Values.ContainsKey("Controller"))
{
fakeRouteData.Values.Add("controller", GetType().Name
.ToLower()
.Replace("controller", ""));
}
HttpContextBase offlineContextBase = new OfflineHttpContext(viewName, request, context);
var offlineControllerContext = new ControllerContext(offlineContextBase, fakeRouteData, this);
// try to use the fake context to get the partial view
var viewResult = ViewEngines.Engines.FindPartialView(offlineControllerContext, viewName);
var viewContext = new ViewContext(offlineControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(offlineControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
}
public class OfflineHttpContext : HttpContextBase
{
private readonly Hashtable _items = new Hashtable();
private IPrincipal _user;
private readonly IHttpRequest _request;
private readonly IContext _context;
private readonly string _relativeUrl;
public OfflineHttpContext(string relativeUrl, IHttpRequest request, IContext context)
{
_relativeUrl = relativeUrl;
_request = request;
_context = context;
}
public override Exception[] AllErrors
{
get { return new Exception[0]; }
}
public override Cache Cache
{
get { return null; }
}
public override HttpRequestBase Request
{
get
{
var serverVariables = new NameValueCollection
{
{"HTTP_HOST", "www.example.com"},
{"APPL_PHYSICAL_PATH", _context.PhysicalPath}
};
var headers = new NameValueCollection();
foreach (var header in _request.Headers)
{
headers.Add(header.Key, header.Value);
}
var formParams = new NameValueCollection();
var queryStringParams = new NameValueCollection();
var cookies = new HttpCookieCollection();
HttpRequestBase httpContext = new OfflineHttpRequest(_relativeUrl, _request.Method, formParams, queryStringParams, cookies, serverVariables, headers);
return httpContext;
}
}
public override HttpResponseBase Response
{
get
{
var httpResponse = new HttpResponse(new StringWriter());
return new HttpResponseWrapper(httpResponse);
}
}
public override IDictionary Items
{
get { return _items; }
}
public override IPrincipal User
{
get
{
if (_user == null)
{
// User is logged in
return new GenericPrincipal(new GenericIdentity("public"), new string[0]);
// User is logged out
// return new GenericPrincipal(new GenericIdentity(""), new string[0]);
}
return _user;
}
set { _user = value; }
}
}
public class OfflineHttpRequest : HttpRequestBase
{
private readonly HttpCookieCollection _cookies;
private readonly NameValueCollection _formParams;
private readonly NameValueCollection _queryStringParams;
private readonly NameValueCollection _headers;
private readonly NameValueCollection _serverVariables;
private readonly string _relativeUrl;
private readonly Uri _url;
private readonly Uri _urlReferrer;
private readonly string _httpMethod;
public OfflineHttpRequest(
string relativeUrl,
string httpMethod,
NameValueCollection formParams,
NameValueCollection queryStringParams,
HttpCookieCollection cookies,
NameValueCollection serverVariables,
NameValueCollection headers)
{
_httpMethod = httpMethod;
_relativeUrl = relativeUrl;
_formParams = formParams;
_queryStringParams = queryStringParams;
_cookies = cookies;
_serverVariables = serverVariables;
_headers = headers;
//ensure collections are not null
if (_formParams == null)
{
_formParams = new NameValueCollection();
}
if (_queryStringParams == null)
{
_queryStringParams = new NameValueCollection();
}
if (_cookies == null)
{
_cookies = new HttpCookieCollection();
}
if (_serverVariables == null)
{
_serverVariables = new NameValueCollection();
}
if (_headers == null)
{
_headers = new NameValueCollection();
}
}
public OfflineHttpRequest(
string relativeUrl,
string httpMethod,
Uri url,
Uri urlReferrer,
NameValueCollection formParams,
NameValueCollection queryStringParams,
HttpCookieCollection cookies,
NameValueCollection serverVariables,
NameValueCollection headers)
: this(relativeUrl, httpMethod, formParams, queryStringParams, cookies, serverVariables, headers)
{
_url = url;
_urlReferrer = urlReferrer;
_headers = headers;
}
public OfflineHttpRequest(
string relativeUrl,
Uri url,
Uri urlReferrer)
: this(relativeUrl, HttpVerbs.Get.ToString("g"), url, urlReferrer, null, null, null, null, null)
{
}
public override NameValueCollection ServerVariables
{
get
{
return _serverVariables;
}
}
public override NameValueCollection Form
{
get { return _formParams; }
}
public override NameValueCollection QueryString
{
get { return _queryStringParams; }
}
public override NameValueCollection Headers
{
get { return _headers; }
}
public override HttpCookieCollection Cookies
{
get { return _cookies; }
}
public override string AppRelativeCurrentExecutionFilePath
{
get { return _relativeUrl; }
}
public override Uri Url
{
get
{
return _url;
}
}
public override Uri UrlReferrer
{
get
{
return _urlReferrer;
}
}
public override string Path
{
get
{
if (_relativeUrl != null && _relativeUrl.StartsWith("~/"))
{
return _relativeUrl.Remove(0, 1);
}
return null;
}
}
public override string PathInfo
{
get
{
return "";
}
}
public override string PhysicalApplicationPath
{
get
{
return _serverVariables.Get("APPL_PHYSICAL_PATH");
}
}
public override string PhysicalPath
{
get
{
var file = "";
if (Path != null && Path.StartsWith("/"))
{
file = Path.Remove(0, 1);
}
if (PhysicalApplicationPath != null)
{
return PhysicalApplicationPath + "\\" + file.Replace('/', '\\');
}
return null;
}
}
public override string HttpMethod
{
get
{
return _httpMethod;
}
}
public override string UserHostAddress
{
get { return null; }
}
public override string RawUrl
{
get { return null; }
}
public override bool IsSecureConnection
{
get { return false; }
}
public override bool IsAuthenticated
{
get
{
return false;
}
}
public override string UserAgent
{
get
{
var agent = _headers.Get("User-Agent") ??
"Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html)";
return agent;
}
}
public override HttpBrowserCapabilitiesBase Browser
{
get
{
var browser = new HttpBrowserCapabilities
{
Capabilities = new Hashtable { { string.Empty, UserAgent } }
};
var factory = new BrowserCapabilitiesFactory();
factory.ConfigureBrowserCapabilities(new NameValueCollection(), browser);
return new HttpBrowserCapabilitiesWrapper(browser);
}
}
}
【问题讨论】:
-
所以这就是我正在尝试使用的,但是抛出了一个与 VirtualPath 为空相关的异常。当我在这里使用我的假上下文时: ... ViewEngines.Engines.FindPartialView(offlineControllerContext, viewName); ...在后台 VirtualPathProvider 使用的是 ASP.Net HttpContext,而不是我的假上下文。
标签: c# asp.net-mvc partial-views web-parts httpcontext