从 url 返回 HTML 的 HtmlHelper (essentialy proxy)
本文关键字:essentialy proxy HtmlHelper url 返回 HTML | 更新日期: 2023-09-27 18:31:19
我正在尝试创建一个基于Html.RenderAction工作方式的HtmlHelper。它与RenderAction的不同之处在于,与"ActionName"和"ControllerName"一起,它采用一个字符串,而该字符串又对应于Web.Config中的值。配置中的此值是 URL 的值。
这样做的原因是,尽管我的控制器/操作在它自己的本机项目中完美运行,但我需要从它的兄弟项目中获取此控制器/操作的结果。我打算通过使用助手构建所需的 URL 以及每个兄弟项目的 Web.Config 中当前保存的详细信息来做到这一点。
我已经编码了以下内容:
public static void RenderActionToSpecifiedAssembly(this HtmlHelper helper, string actionName, string controllerName, string parentAssembly)
{
var uriFromWebConfig = new Uri(ConfigurationManager.AppSettings[parentAssembly]);
//uriFromWebConfig == "http://ProjectNumberOne.com/"
var parentUri = new Uri(uriFromWebConfig);
var path = controllerName + "/" + actionName;
var redirect = new Uri(parentUri, path).AbsoluteUri;
//var redirect == "http://ProjectNumberOne.com/MyController/MyAction"
//******************
}
我现在正在纠结的是该在******的房子里放什么。我希望这个帮助程序做的是返回 http://ProjectNumberOne.com/MyController/MyAction 的结果。
- 如果我在地址栏中键入此 URL,它将返回预期的 html 页面。
- 如果我在父项目中使用 Html.RenderAction("MyAction","MyController"),它会返回预期的 html 页面。
我不知道该怎么做的是在帮助程序的末尾指定同级项目的返回 URL,以便从中获取生成的 html。
有什么想法吗?
你帖子中的一些细节使得你很难确定你是想通过使用反射还是使用 http 来实现你的目标(或者你可能不在乎,只要你能得到你想要的结果)。
我不建议您尝试利用反射来完成此操作。 (这有很多原因,但重要的是使用HTTP会更容易,更直接)
根据您发布的内容,我将使用的方法是创建一个HtmlHelper
,该呈现具有所需URL的IFRAME
标签作为src
。
像这样的东西(顺便说一句,这里有很多防御性编码的机会):
public static MvcHtmlString RenderIFrameForCompanionSite(this HtmlHelper helper, string actionName, string controllerName, string baseUrlSettingKey)
{
var baseUrlFromWebConfig = ConfigurationManager.AppSettings[baseUrlSettingKey];
var companionSiteUri = new Uri(baseUrlFromWebConfig);
var path = controllerName + "/" + actionName;
var redirect = new Uri(companionSiteUri, path).AbsoluteUri;
return new MvcHtmlString("<iframe style='width: 100%' src='" + redirect + "'></iframe>");
}
ProjectTwo
网站中的视图将引用ProjectOne
中的操作,如下所示:
@Html.RenderIFrameForCompanionSite("MyAction", "MyController", "ProjectOne")
我假设您的应用程序有业务需要位于不同的站点/项目中。 但是,如果这不是强制性的,那么您可以考虑是否可以以不同的方式组织相关内容(例如具有多个区域的单个站点而不是多个站点),这将使您更容易在它们之间共享内容/行为。
我发现尽管David提供的IFRAME方法可以根据需要工作,但使用IFRAME仍然让我感到不安。这篇文章让我意识到它们不是那么好:为什么不在页面内容中使用 Iframe 的充分理由
我发现以下实现达到了它的目的,并给了我所需的结果:
public static IHtmlString RenderActionToSpecifiedAssembly(this HtmlHelper helper, string actionName, string controllerName, string parentAssembly)
{
var parentWebConfigarentValue = new Uri(ConfigurationManager.AppSettings[parentAssembly]);
var path = controllerName + "/" + actionName;
var redirect = new Uri(parentWebConfigarentValue, path).AbsoluteUri;
var request = (HttpWebRequest)WebRequest.Create(redirect);
var result = (HttpWebResponse)request.GetResponse();
String responseString;
using (Stream stream = result.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
responseString = reader.ReadToEnd();
}
return new HtmlString(responseString);
}
使用这种方法允许我向父控制器/操作发出请求,将其写入字符串,然后将 HTML 返回到要呈现的页面。工作魅力!:)
您的解决方案可以更好地解释您想要什么,但非常不灵活。如果需要将其他路由值传递给请求,该怎么办?最好通过提供可用于构建所需的任何 URL 的重载来模仿 UrlHelper 类。
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
public static class HtmlHelperExtensions
{
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string parentAssembly)
{
return RenderActionToSpecifiedAssembly(
helper, actionName, null, null, null, parentAssembly);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, object routeValues,
string parentAssembly)
{
return RenderActionToSpecifiedAssembly(helper, actionName,
null, new RouteValueDictionary(routeValues), null, parentAssembly);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string controllerName,
string parentAssembly)
{
return RenderActionToSpecifiedAssembly(helper, actionName,
controllerName, null, null, parentAssembly);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, RouteValueDictionary routeValues,
string parentAssembly)
{
return RenderActionToSpecifiedAssembly(helper, actionName,
null, routeValues, null, parentAssembly);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string controllerName,
object routeValues, string parentAssembly)
{
return RenderActionToSpecifiedAssembly(helper, actionName,
controllerName, new RouteValueDictionary(routeValues),
null, parentAssembly);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string controllerName,
RouteValueDictionary routeValues, string parentAssembly)
{
return RenderActionToSpecifiedAssembly(helper, actionName,
controllerName, routeValues, parentAssembly, null);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string controllerName,
object routeValues, string protocol, string parentAssembly)
{
return RenderActionToSpecifiedAssembly(helper, actionName,
controllerName, routeValues, protocol, parentAssembly, null);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string controllerName,
RouteValueDictionary routeValues, string parentAssembly, string port)
{
var hostName = ConfigurationManager.AppSettings[parentAssembly];
var url = GenerateContentUrl(helper, actionName,
controllerName, routeValues, null, hostName, port);
return RenderContents(url);
}
public static IHtmlString RenderActionToSpecifiedAssembly(
this HtmlHelper helper, string actionName, string controllerName,
object routeValues, string protocol, string parentAssembly, string port)
{
var hostName = ConfigurationManager.AppSettings[parentAssembly];
var url = GenerateContentUrl(helper, actionName,
controllerName, new RouteValueDictionary(routeValues),
protocol, hostName, port);
return RenderContents(url);
}
private static string GenerateContentUrl(this HtmlHelper helper,
string actionName, string controllerName, RouteValueDictionary routeValues,
string protocol, string hostName, string port)
{
var currentUri = helper.ViewContext.RequestContext.HttpContext.Request.Url;
// Ensure we have an absolute path
if (string.IsNullOrEmpty(protocol) && string.IsNullOrEmpty(hostName))
{
// Match the scheme of the current request so we don't get a
// security warning in the browser.
protocol = currentUri.Scheme;
}
// Allow caller to override the port so it doesn't have
// to be the same as the current request.
string currentUrl = currentUri.Scheme + Uri.SchemeDelimiter
+ currentUri.DnsSafeHost;
if (!string.IsNullOrEmpty(port))
{
currentUrl += ":" + port;
}
currentUrl += "/";
var homePageUri = new Uri(new Uri(currentUrl, UriKind.Absolute), "/");
// Create a TextWriter with null stream as a backing stream
// which doesn't consume resources
using (var nullWriter = new StreamWriter(Stream.Null))
{
// Create a fake context at the home page to ensure that ambient values
// from the request are excluded from the generated URL.
// See: https://aspnetwebstack.codeplex.com/workitem/1346
var httpContext = CreateHttpContext(homePageUri, nullWriter);
var requestContext = new RequestContext(httpContext, new RouteData());
return UrlHelper.GenerateUrl(null, actionName, controllerName,
protocol, hostName, null, routeValues, helper.RouteCollection,
requestContext, true);
}
}
private static HttpContextBase CreateHttpContext(Uri uri, TextWriter writer)
{
if (uri == null)
throw new ArgumentNullException("uri");
if (writer == null)
throw new ArgumentNullException("writer");
var request = new HttpRequest(string.Empty, uri.ToString(), uri.Query);
var response = new HttpResponse(writer);
var httpContext = new HttpContext(request, response);
return new HttpContextWrapper(httpContext);
}
private static IHtmlString RenderContents(string url)
{
var request = (HttpWebRequest)WebRequest.Create(url);
var result = (HttpWebResponse)request.GetResponse();
String responseString;
using (Stream stream = result.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
responseString = reader.ReadToEnd();
}
return new HtmlString(responseString);
}
}
您可能还希望从配置值中解析端口,以便您可以在那里同时配置 http 和 https URL,以便将它们与主机名紧密绑定在一起,这可能会消除一些重载。在这种情况下,您可能应该使用当前请求的协议来确定要检索的哪个(HTTP 或 HTTPS)配置值,并删除作为传入值的协议。