2016-09-29 6 views
2

私はEmailerクラスを持っています。依存関係注入を使用して、電子メールで送信するビューの内容を取得する電子メールを送信しています。ビューは、使用するなど、基本となるURLのヘルパーへの呼び出しが含まれていない限り、私が持っているプロセスは、素晴らしい作品。このようなタグ:ASP.NET Coreの文字列へのURLを含むRazor Viewをレンダリングします

ここ
<a asp-controller="Project" asp-action="List">Open</a> 

私は文字列にビューをレンダリングするために使用していたコードは次のとおりです。

private string renderViewAsString<TModel>(string folder, string viewName, TModel model) 
{ 
    var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider }; 
    var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); 
    var viewEngineResult = _viewEngine.FindView(actionContext, folder + "/" + viewName, false); 
    var view = viewEngineResult.View; 

    var viewData = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()); 
    viewData.Model = model; 

    var tempData = new TempDataDictionary(httpContext, _tempDataProvider); 

    using (var output = new StringWriter()) 
    { 
    var viewContext = new ViewContext(actionContext, view, viewData, tempData, output, new HtmlHelperOptions());   
    var task = view.RenderAsync(viewContext); 
    task.Wait(); 

    return output.ToString(); 
    } 
} 

_serviceProviderはタイプIServiceProviderであり、_viewEngineはタイプIRazorViewEngineであり、どちらもコンストラクタに挿入されます。

それはURLヘルパーを参照している場合、それはtask.Wait()ラインでこの例外を生成します。コールスタックとしてこれと

Index was out of range. Must be non-negative and less than the size of the collection. 
Parameter name: index 

at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) 
at System.Collections.Generic.List`1.get_Item(Int32 index) 
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.get_Router() 
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(String routeName, RouteValueDictionary values) 
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext) 
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values, String protocol, String host, String fragment) 
at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateActionLink(ViewContext viewContext, String linkText, String actionName, String controllerName, String protocol, String hostname, String fragment, Object routeValues, Object htmlAttributes) 
at Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper.Process(TagHelperContext context, TagHelperOutput output) 
at Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output) 
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>d__0.MoveNext() 

私はこの問題を回避するにはどうすればよいですA要素や電子メールの内容をハードコーディングする必要はありませんか?

答えて

8

私はそれが仕事を得ることができました。

まず私は、コンストラクタのパラメータのDIオブジェクトとしてこれを追加しました::コンストラクタでこの

IHttpContextAccessor accessor 

そして、それはそれを提供するの問題だったように、コールスタックには、ルータを見つける言及していません

_context = accessor.HttpContext; 

は、その後、私はこれに関数を変更:

private string renderViewAsString<TModel>(string folder, string viewName, TModel model) 
{ 
    var actionContext = new ActionContext(_context, new RouteData(), new ActionDescriptor()); 
    var viewEngineResult = _viewEngine.FindView(actionContext, folder + "/" + viewName, false); 
    var view = viewEngineResult.View; 

    var viewData = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()); 
    viewData.Model = model; 

    var tempData = new TempDataDictionary(_context, _tempDataProvider); 

    using (var output = new StringWriter()) 
    { 
    var viewContext = new ViewContext(actionContext, view, viewData, tempData, output, new HtmlHelperOptions()); 
    viewContext.RouteData = _context.GetRouteData(); //set route data here 

    var task = view.RenderAsync(viewContext); 
    task.Wait(); 

    return output.ToString(); 
    } 
} 
+0

ありがとう!その仕事は完璧に今! –

+0

今日はこの修正が必要でしたので、ドキュメントを書いてうれしいです。ありがとうございました! –

+0

これは私を救った!これはASP CORE 2で動作します。誰かを助けることを願っています。 –

0

これは、1つのIです2.0

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Mvc.Abstractions; 
using Microsoft.AspNetCore.Mvc.ModelBinding; 
using Microsoft.AspNetCore.Mvc.Razor; 
using Microsoft.AspNetCore.Mvc.Rendering; 
using Microsoft.AspNetCore.Mvc.ViewEngines; 
using Microsoft.AspNetCore.Mvc.ViewFeatures; 
using Microsoft.AspNetCore.Routing; 

namespace Website 
{ 
    public class RazorViewToStringRenderer 
    { 
     private readonly IHttpContextAccessor accessor; 
     private readonly IRazorViewEngine viewEngine; 
     private readonly IServiceProvider serviceProvider; 
     private readonly ITempDataProvider tempDataProvider; 

     public RazorViewToStringRenderer(
      IHttpContextAccessor accessor, 
      IRazorViewEngine viewEngine, 
      IServiceProvider serviceProvider, 
      ITempDataProvider tempDataProvider) 
     { 
      this.accessor = accessor; 
      this.viewEngine = viewEngine; 
      this.serviceProvider = serviceProvider; 
      this.tempDataProvider = tempDataProvider; 
     } 

     public string RenderViewToString<TModel>(string viewLocation, TModel model) 
     { 
      HttpContext httpContext = accessor.HttpContext; 

      httpContext.RequestServices = serviceProvider; 

      ActionContext actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); 

      IView view = FindView(actionContext, viewLocation); 

      using (StringWriter stringWriter = new StringWriter()) 
      { 
       ViewDataDictionary<TModel> viewDataDictionary = new ViewDataDictionary<TModel>(
        new EmptyModelMetadataProvider(), 
        new ModelStateDictionary()); 

       viewDataDictionary.Model = model; 

       TempDataDictionary tempDataDictionary = new TempDataDictionary(
        actionContext.HttpContext, 
        tempDataProvider); 

       HtmlHelperOptions htmlHelperOptions = new HtmlHelperOptions(); 

       ViewContext viewContext = new ViewContext(
        actionContext, 
        view, 
        viewDataDictionary, 
        tempDataDictionary, 
        stringWriter, 
        htmlHelperOptions); 

       viewContext.RouteData = accessor.HttpContext.GetRouteData(); 

       view.RenderAsync(viewContext).Wait(); 

       return stringWriter.ToString(); 
      } 
     } 

     private IView FindView(ActionContext actionContext, string viewLocation) 
     { 
      ViewEngineResult getViewResult = viewEngine.GetView(null, viewLocation, true); 

      if (getViewResult.Success) 
      { 
       return getViewResult.View; 
      } 

      ViewEngineResult findViewResult = viewEngine.FindView(actionContext, viewLocation, true); 

      if (findViewResult.Success) 
      { 
       return findViewResult.View; 
      } 

      IEnumerable<string> searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations); 

      string message = string.Join(
       Environment.NewLine, 
       new[] { $"Unable to find view '{viewLocation}'. The following locations were searched:" }.Concat(searchedLocations)); ; 

      throw new Exception(message); 
     } 
    } 
} 

がStartup.csに覚えているASP.NETコアで使用 - >ます。public void ConfigureServices(IServiceCollection serviceCollectionは)私はだけではないよ知っているこの

serviceCollection.AddSingleton<RazorViewToStringRenderer>(); 
関連する問題