Как заменить URL-адреса в обработанном HTML с помощью ASP.NET MVC ActionFilter

Я пытаюсь создать ActionFilter, чтобы заменить текст в моем HTML. Обычно, когда сервер использует SSL, я хочу заменить ссылки на мой CDN (http://cdn.example.com) ссылками непосредственно на мой сервер (https://www.example.com). Итак, структура выглядит примерно так (я предполагаю, что мне следует начать с OnResultExecuted):

public class CdnSslAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if(filterContext.HttpContext.Request.IsSecureConnection)
        {
            // when the connection is secure,
            // somehow replace all instances of http://cdn.example.com
            // with https://www.example.com
        }
    }
}

Это будет использоваться в моих защищенных контроллерах:

[CdnSsl] 
public class SecureController : Controller
{
}

Причина, по которой я хочу это сделать, заключается в том, что мой CDN не поддерживает SSL. И на главных страницах есть ссылки на ресурсы CDN. Пример:

<link href="http://cdn.example.com/Content/base.css" rel="stylesheet" type="text/css" />

person Keltex    schedule 12.12.2010    source источник


Ответы (4)


В итоге я использовал вариант этого сообщения в блоге:

http://arranmaclean.wordpress.com/2010/08/10/minify-html-with-net-mvc-actionfilter/

с моим собственным фильтром:

public class CdnSslAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsSecureConnection)
        {
            var response = filterContext.HttpContext.Response;
            response.Filter = new CdnSslFilter(response.Filter);
        }
    }
}

Тогда фильтр будет выглядеть так (код для краткости опущен):

public class CdnSslFilter : Stream
{
    private Stream _shrink;
    private Func<string, string> _filter;

    public CdnSslFilter(Stream shrink)
    {
        _shrink = shrink;
        _filter = s => Regex.Replace(s,@"http://cdn\.","https://www.", RegexOptions.IgnoreCase);
    }

    //overridden functions omitted for clarity. See above blog post.

    public override void Write(byte[] buffer, int offset, int count)
    {
        // capture the data and convert to string 
        byte[] data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string s = Encoding.Default.GetString(buffer);

        // filter the string
        s = _filter(s);

        // write the data to stream 
        byte[] outdata = Encoding.Default.GetBytes(s);
        _shrink.Write(outdata, 0, outdata.GetLength(0));
    }
}
person Keltex    schedule 12.12.2010

Я не знаю, но ответ от @Haacked на этом вопрос может помочь.

person Nicolas Cadilhac    schedule 12.12.2010

Выполнить замену сгенерированного вывода внутри фильтра действий было бы немного сложно.

Более простой подход (если вы можете редактировать свои главные страницы) - это написать новый вспомогательный метод Html (аналогичный помощнику Html.Content()), который будет условно выдавать правильный URL-адрес. Если вы хотите, чтобы эта замена происходила только для определенных контроллеров, тогда у вас все еще может быть фильтр действий, но все, что он сделает, - это установить некоторый флаг в Request.Items, и ваш помощник сможет проверить этот флаг.

person marcind    schedule 12.12.2010

Я предлагаю следовать подходу @ marcind, одна из возможностей - использовать собственный метод расширения для создания правильного URL-адреса в зависимости от текущей схемы URL-адресов.

public static MvcHtmlString CdnActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName)
{
    if(helper.ViewContext.HttpContext.Request.IsSecureConnection)
    {
        return helper.ActionLink(linkText, actionName, controllerName, "https", "www.yourhost.com"...);
    }
    return helper.ActionLink(linkText, actionName, controllerName);
}

Одним из недостатков этого подхода является то, что вам нужно будет заменить все ваши текущие вызовы ActionLink в ваших представлениях (или, по крайней мере, те, которые вам нужны) вызовом этого метода расширения.

person uvita    schedule 12.12.2010
comment
Все зависит от того, работает ли разработчик с исходным кодом, которым он может не владеть. Я разрабатываю плагин для системы, в которой мне не разрешено изменять код. Это означает, что мне нужно изменить ответ, чтобы изменить определенные части пользовательского интерфейса. - person Razor; 01.05.2017