从 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。

有什么想法吗?

从 url 返回 HTML 的 HtmlHelper (essentialy proxy)

你帖子中的一些细节使得你很难确定你是想通过使用反射还是使用 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)配置值,并删除作为传入值的协议。