从url(essentialy代理)返回HTML的HtmlHelper

时间:2014-11-21 15:33:00

标签: c# asp.net-mvc razor html-helper

我尝试创建一个基于Html.RenderAction工作方式的HtmlHelper。与RenderAction不同的方式是" ActionName"和" ControllerName",它取一个字符串,该字符串又对应于Web.Config中的值。配置中的此值是URL的值。

这样做的原因是虽然我的Controller / Action在它自己​​的原生项目中完美运行,但我需要从它的兄弟项目中获得此Controller / Action的结果。我打算通过使用帮助程序构建所需的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 的结果。

  • 如果我在地址栏中输入此网址,则会返回预期的html网页。
  • 如果我在父项目中使用 Html.RenderAction(" MyAction"," MyController"),则会返回预期的html页面。

我不知道该怎么做是在帮助程序的末尾指定兄弟项目的返回URL以从中获取生成的html。

有什么想法吗?

3 个答案:

答案 0 :(得分:0)

您帖子中的某些细节很难确定您是否希望通过反射或使用 http 来实现目标(或者您可能不在乎只要你能得到你想要的结果。

我不建议您尝试利用反射来实现此目的。 (这有很多原因,但重要的是使用http将变得更容易,更直接)

根据您发布的内容,我将使用的方法是创建一个HtmlHelper,其IFRAME标记所需的网址为src

像这样的东西(这里有很多机会进行防御性编码BTW):

    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")

我假设您的应用程序有业务需要在不同的站点/项目中。但是,如果这不是强制性的,那么您可以考虑是否可以以不同方式组织相关内容(例如,具有多个区域而不是多个站点的单个站点),这将使您更容易共享它们之间的内容/行为。

答案 1 :(得分:0)

我发现尽管David提供的IFRAME方法按要求工作,但使用IFRAME仍然让我感到不安。这篇文章让我意识到他们并不是那么伟大:Good Reasons why not to use Iframes in page content

我发现以下实现符合它的目的并给了我所需的结果:

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);
}

使用这种方法,我可以向Parent Controller / Action发出请求,将其写入字符串然后将HTML返回到要呈现的页面。有魅力! :)

答案 2 :(得分:0)

您的解决方案可以更好地解释您的需求,但非常不灵活。如果您需要将其他路由值传递给请求,该怎么办?最好通过提供可用于构建任何所需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)配置值,并将协议作为传入值删除。