0

たくさんのファイルを1つの「ファイル」に結合する必要があります。ただし、これらのファイルの一部を動的にする必要があるため、動的リソースを返すアクションがあります。例えば

[OutputCache(VaryByParam = "culture", Duration = 3600)]
public ActionResult Settings(string culture)
{
    CultureInfo cultureInfo;
    try
    {
        cultureInfo = new CultureInfo(culture);
    }
    catch
    {
        cultureInfo = Configuration.Current.DefaultCulture;
    }
    var sb = new StringBuilder();
    sb.AppendFormat("Cms.Settings.Language = '{0}';", cultureInfo.TwoLetterISOLanguageName);

    sb.AppendFormat("Cms.Settings.DayNames = [{0}];", string.Join(",", cultureInfo.DateTimeFormat.DayNames.Select(d => "\"" + d + "\"")));
    sb.AppendFormat("Cms.Settings.ShortDayNames = [{0}];", string.Join(",", cultureInfo.DateTimeFormat.AbbreviatedDayNames.Select(d => "\"" + d + "\"")));
    sb.AppendFormat("Cms.Settings.FirstDay = {0};", (int)cultureInfo.DateTimeFormat.FirstDayOfWeek);

    sb.AppendFormat("Cms.Settings.ShortMonthNames = [{0}];", string.Join(",", cultureInfo.DateTimeFormat.AbbreviatedMonthNames.Take(12).Select(m => "\"" + m + "\"")));

    var languages = new[]{cultureInfo.TwoLetterISOLanguageName};
    var keys = translator.GetKeys(languages[0]);
    foreach (var key in keys)
    {
        sb.AppendFormat("Cms.Settings.Texts['{0}'] = '{1}';", key, translator.GetText(key, key, languages));
    }

    // TODO: from settings
    sb.AppendFormat("Cms.Settings.IconDir = '{0}';", VirtualPathUtility.ToAbsolute("~/img/icons/"));
    return JavaScript(sb.ToString());
}

私がやりたいのは、それらの物理ファイルとActionResultsを1つの「ファイル」に結合することです。結合を行うためにこのアクションを実行しましたが、パスごとにアクションの出力を取得する簡単な方法がわかりません。

// files is like "jquery.js,/js/settings?culture=fi,jquery-ui.js,..."
[OutputCache(VaryByParam = "files", Duration=3600)]
public ActionResult Bundle(string files)
{
    var paths = files.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    var sb = new StringBuilder();
    foreach (var path in paths)
    {
        appendFile(sb, path);
    }
    return JavaScript(sb.ToString());
}
private void appendFile(StringBuilder sb, string path)
{
    if (/* path is file on disk */)
    {
        var filename = Server.MapPath(path);
        if (!System.IO.File.Exists(filename))
        {
            return;
        }
        sb.Append(System.IO.File.ReadAllText(filename));
    }
    else if(/* is action */)
    {
        // how do I get the output?
        var output = getActionOutput(path);
        sb.Append(output);
    }
}

私が試したもう1つのオプションは、動的ファイルにVirtualPathProviderを使用することでしたが、何らかの理由で、ディスク上にないファイルに対して「GetFile」が呼び出されませんでした。

public class JsVirtualPathProvider : VirtualPathProvider
{
    public override bool FileExists(string virtualPath)
    {
        if (virtualPath == "~/js/settings/fi.js")
        {
            // this was called
            return true;
        }
        return base.FileExists(virtualPath);
    }
    public override VirtualFile GetFile(string virtualPath)
    {
        // never called for this "file"?
        if (virtualPath == "~/js/settings/fi.js")
        {
                return new JsFile(virtualPath, "Cms.Settings.Foo = 'Bar';");
        }
        return base.GetFile(virtualPath);
    }

    class JsFile : VirtualFile
    {
        private readonly string content;
        public JsFile(string virtualPath, string content) : base(virtualPath)
        {
                this.content = content;
        }
        public override Stream Open()
        {
                return new MemoryStream(Encoding.UTF8.GetBytes(content), false);
        }
    }
}

物理ファイルを動的/仮想ファイルと組み合わせる最も簡単な方法は何でしょうか?

4

2 に答える 2

0

次のコードでアクションの出力を取得しました。

var url = string.Format("{0}://{1}", Request.Url.Scheme, Request.Url.Host);
if (Request.Url.Port != 80)
{
    url += ":" + Request.Url.Port;
}
url += path;
var writer = new StringWriter(sb);
var httpContext = new HttpContext(new HttpRequest("", url, ""), new HttpResponse(writer));
HttpContextBase httpContextBase = new HttpContextWrapper(httpContext);
var routeData = System.Web.Routing.RouteTable.Routes.GetRouteData(httpContextBase);
var handler = RouteData.RouteHandler.GetHttpHandler(new RequestContext(httpContextBase,routeData));
handler.ProcessRequest(httpContext);

何らかの理由で、呼び出されたアクション(設定)のQueryStringValueProviderには呼び出し元のアクション(バンドル)の値が含まれていたため、パスを/js/settings/{culture}(以前は/js/settings?culture={culture})に変更しました。

于 2012-05-27T07:43:23.637 に答える
-1
else if(/* is action */)
{
    // how do I get the output?

    // You need to send an HTTP request (for example using WebClient) 
    // to fetch the result of the execution of this action
    ...
}
于 2012-05-24T13:31:05.810 に答える