1

안녕하십니까. 코드를 발견 한 특정 시간에 이메일을 보내려고합니다. global.asax.cs에 이메일 기능에서Thread.Timer with HttpContext가 작동하지 않습니다.

protected void Application_Start() 
{ 
    ETHOS.Controllers.HomeController mail = new Controllers.HomeController(); 
    mail.ScheduleService(); 
    private void SchedularCallback(object e) 
    { 
     this.WriteToFile("Simple Service Log: {0}"); 
     getData();//Email function 
     this.ScheduleService(); 
    } 
    public void ScheduleService() 
    { 
     try 
     { 
      Schedular = new Timer(new TimerCallback(SchedularCallback)); 
      string mode = "DAILY"; 
      this.WriteToFile("Simple Service Mode: " + mode + " {0}"); 
      //Set the Default Time. 
      //DateTime d = DateTime.Today; 
      //TimeSpan t = new TimeSpan(12, 40, 00); 
      //DateTime scheduledTime = d.Date + t; 
      DateTime scheduledTime = DateTime.Now.AddSeconds(30); 
      if (DateTime.Now > scheduledTime) 
      { 
       //If Scheduled Time is passed set Schedule for the next day. 
       // scheduledTime = scheduledTime.AddDays(1); 
       scheduledTime = scheduledTime.AddDays(1); 
      } 
      TimeSpan timeSpan = scheduledTime.Subtract(DateTime.Now); 
      string schedule = string.Format("{0} day(s) {1} hour(s) {2} minute(s) {3} seconds(s)", timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); 
      this.WriteToFile("Simple Service scheduled to run after: " + schedule + " {0}"); 
      //Get the difference in Minutes between the Scheduled and Current Time. 
      int dueTime = Convert.ToInt32(timeSpan.TotalMilliseconds); 

      //Change the Timer's Due Time. 
      Schedular.Change(dueTime, Timeout.Infinite); 
     } 
     catch (Exception ex) 
     { 
      WriteToFile("Simple Service Error on: {0} " + ex.Message + ex.StackTrace); 
     } 
    } 

파일 내가 Gmail을 통해 몸에 이메일을 보내고있다 내가 문자열로 렌더링 내 면도기보기로 문자열 클래스 부분 뷰를 렌더링하고있어

string body = ViewRenderer.RenderPartialView("~/Views/Shared/Email.cshtml", LEM); 

문제는 HttpContext.Current.It가 HttpContext.Current = null을 표시하지 않는다는 것입니다. 난 둘 다 스레드를 만드는 것 같아 왜 그렇게 HttpContext를 받고 있지 않습니다 그래서 내가 어떻게 모두 httpContext와 함께 사용할 수 있습니다. 는 여기 HttpContext는 HTTP 요청의 수명 내에서만 사용할 수 있습니다

public class ViewRenderer:ETHOS.Controllers.HomeController 
     {/// <summary> 
    /// Required Controller Context 
    /// </summary> 
    protected ControllerContext Context { get; set; } 

    /// <summary> 
    /// Initializes the ViewRenderer with a Context. 
    /// </summary> 
    /// <param name="controllerContext"> 
    /// If you are running within the context of an ASP.NET MVC request pass in 
    /// the controller's context. 
    /// Only leave out the context if no context is otherwise available. 
    /// </param> 
    public ViewRenderer(ControllerContext controllerContext = null) 
    { 
     System.Web.HttpContext ctx = (System.Web.HttpContext) Session["ctx"]; 
     // Create a known controller from HttpContext if no context is passed 
     if (controllerContext == null) 
     { 
      if (System.Web.HttpContext.Current != null) 
       controllerContext = CreateController<EmptyController>().ControllerContext; 
      else 
       throw new InvalidOperationException(
        "ViewRenderer must run in the context of an ASP.NET " + 
        "Application and requires HttpContext.Current to be present."); 
     } 
     Context = controllerContext; 
    } 

    /// <summary> 
    /// Renders a full MVC view to a string. Will render with the full MVC 
    /// View engine including running _ViewStart and merging into _Layout   
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to render the view with</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public string RenderViewToString(string viewPath, object model = null) 
    { 
     return RenderViewToStringInternal(viewPath, model, false); 
    } 

    /// <summary> 
    /// Renders a full MVC view to a writer. Will render with the full MVC 
    /// View engine including running _ViewStart and merging into _Layout   
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to render the view with</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public void RenderView(string viewPath, object model, TextWriter writer) 
    { 
     RenderViewToWriterInternal(viewPath, writer, model, false); 
    } 


    /// <summary> 
    /// Renders a partial MVC view to string. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public string RenderPartialViewToString(string viewPath, object model = null) 
    { 
     return RenderViewToStringInternal(viewPath, model, true); 
    } 

    /// <summary> 
    /// Renders a partial MVC view to given Writer. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="writer">Writer to render the view to</param> 
    public void RenderPartialView(string viewPath, object model, TextWriter writer) 
    { 
     RenderViewToWriterInternal(viewPath, writer, model, true); 
    } 

    /// <summary> 
    /// Renders a partial MVC view to string. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="controllerContext">Active Controller context</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public static string RenderView(string viewPath, object model = null, 
            ControllerContext controllerContext = null) 
    { 
     ViewRenderer renderer = new ViewRenderer(controllerContext); 
     return renderer.RenderViewToString(viewPath, model); 
    } 

    /// <summary> 
    /// Renders a partial MVC view to the given writer. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="writer">Writer to render the view to</param> 
    /// <param name="controllerContext">Active Controller context</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public static void RenderView(string viewPath, TextWriter writer, object model, 
            ControllerContext controllerContext) 
    { 
     ViewRenderer renderer = new ViewRenderer(controllerContext); 
     renderer.RenderView(viewPath, model, writer); 
    } 

    /// <summary> 
    /// Renders a partial MVC view to string. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="controllerContext">Active Controller context</param> 
    /// <param name="errorMessage">optional out parameter that captures an error message instead of throwing</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public static string RenderView(string viewPath, object model, 
            ControllerContext controllerContext, 
            out string errorMessage) 
    { 
     errorMessage = null; 
     try 
     { 
      ViewRenderer renderer = new ViewRenderer(controllerContext); 
      return renderer.RenderViewToString(viewPath, model); 
     } 
     catch (Exception ex) 
     { 
      errorMessage = ex.GetBaseException().Message; 
     } 
     return null; 
    } 

    /// <summary> 
    /// Renders a partial MVC view to the given writer. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="controllerContext">Active Controller context</param> 
    /// <param name="writer">Writer to render the view to</param> 
    /// <param name="errorMessage">optional out parameter that captures an error message instead of throwing</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public static void RenderView(string viewPath, object model, TextWriter writer, 
            ControllerContext controllerContext, 
            out string errorMessage) 
    { 
     errorMessage = null; 
     try 
     { 
      ViewRenderer renderer = new ViewRenderer(controllerContext); 
      renderer.RenderView(viewPath, model, writer); 
     } 
     catch (Exception ex) 
     { 
      errorMessage = ex.GetBaseException().Message; 
     } 
    } 


    /// <summary> 
    /// Renders a partial MVC view to string. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="controllerContext">Active controller context</param> 
    /// <returns>String of the rendered view or null on error</returns> 
    public static string RenderPartialView(string viewPath, object model = null, 
              ControllerContext controllerContext = null) 
    { 
     ViewRenderer renderer = new ViewRenderer(controllerContext); 
     return renderer.RenderPartialViewToString(viewPath, model); 
    } 

    /// <summary> 
    /// Renders a partial MVC view to string. Use this method to render 
    /// a partial view that doesn't merge with _Layout and doesn't fire 
    /// _ViewStart. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">The model to pass to the viewRenderer</param> 
    /// <param name="controllerContext">Active controller context</param> 
    /// <param name="writer">Text writer to render view to</param> 
    /// <param name="errorMessage">optional output parameter to receive an error message on failure</param> 
    public static void RenderPartialView(string viewPath, TextWriter writer, object model = null, 
              ControllerContext controllerContext = null) 
    { 
     ViewRenderer renderer = new ViewRenderer(controllerContext); 
     renderer.RenderPartialView(viewPath, model, writer); 
    } 


    /// <summary> 
    /// Internal method that handles rendering of either partial or 
    /// or full views. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">Model to render the view with</param> 
    /// <param name="partial">Determines whether to render a full or partial view</param> 
    /// <param name="writer">Text writer to render view to</param> 
    protected void RenderViewToWriterInternal(string viewPath, TextWriter writer, object model = null, bool partial = false) 
    { 
     // first find the ViewEngine for this view 
     ViewEngineResult viewEngineResult = null; 
     if (partial) 
      viewEngineResult = ViewEngines.Engines.FindPartialView(Context, viewPath); 
     else 
      viewEngineResult = ViewEngines.Engines.FindView(Context, viewPath, null); 

     if (viewEngineResult == null) 
      throw new FileNotFoundException(); 

     // get the view and attach the model to view data 
     var view = viewEngineResult.View; 
     Context.Controller.ViewData.Model = model; 

     var ctx = new ViewContext(Context, view, 
            Context.Controller.ViewData, 
            Context.Controller.TempData, 
            writer); 
     view.Render(ctx, writer); 
    } 

    /// <summary> 
    /// Internal method that handles rendering of either partial or 
    /// or full views. 
    /// </summary> 
    /// <param name="viewPath"> 
    /// The path to the view to render. Either in same controller, shared by 
    /// name or as fully qualified ~/ path including extension 
    /// </param> 
    /// <param name="model">Model to render the view with</param> 
    /// <param name="partial">Determines whether to render a full or partial view</param> 
    /// <returns>String of the rendered view</returns> 
    private string RenderViewToStringInternal(string viewPath, object model, 
               bool partial = false) 
    { 
     // first find the ViewEngine for this view 
     ViewEngineResult viewEngineResult = null; 
     if (partial) 
      viewEngineResult = ViewEngines.Engines.FindPartialView(Context, viewPath); 
     else 
      viewEngineResult = ViewEngines.Engines.FindView(Context, viewPath, null); 

     if (viewEngineResult == null || viewEngineResult.View == null) 
      throw new FileNotFoundException();//Resources.ViewCouldNotBeFound); 

     // get the view and attach the model to view data 
     var view = viewEngineResult.View; 
     Context.Controller.ViewData.Model = model; 

     string result = null; 

     using (var sw = new StringWriter()) 
     { 
      var ctx = new ViewContext(Context, view, 
             Context.Controller.ViewData, 
             Context.Controller.TempData, 
             sw); 
      view.Render(ctx, sw); 
      result = sw.ToString(); 
     } 

     return result; 
    } 


    /// <summary> 
    /// Creates an instance of an MVC controller from scratch 
    /// when no existing ControllerContext is present  
    /// </summary> 
    /// <typeparam name="T">Type of the controller to create</typeparam> 
    /// <returns>Controller for T</returns> 
    /// <exception cref="InvalidOperationException">thrown if HttpContext not available</exception> 
    public static T CreateController<T>(RouteData routeData = null, params object[] parameters) 
       where T : Controller, new() 
    { 
     // create a disconnected controller instance 
     T controller = (T)Activator.CreateInstance(typeof(T), parameters); 

     // get context wrapper from HttpContext if available 
     HttpContextBase wrapper = null; 
     if (System.Web.HttpContext.Current != null) 
      wrapper = new HttpContextWrapper(System.Web.HttpContext.Current); 
     else 
      throw new InvalidOperationException(
       "Can't create Controller Context if no active HttpContext instance is available."); 

     if (routeData == null) 
      routeData = new RouteData(); 

     // add the controller routing if not existing 
     if (!routeData.Values.ContainsKey("controller") && !routeData.Values.ContainsKey("Controller")) 
      routeData.Values.Add("controller", controller.GetType().Name 
                 .ToLower() 
                 .Replace("controller", "")); 

     controller.ControllerContext = new ControllerContext(wrapper, routeData, controller); 
     return controller; 
    } 

} 

/// <summary> 
/// Empty MVC Controller instance used to 
/// instantiate and provide a new ControllerContext 
/// for the ViewRenderer 
/// </summary> 
public class EmptyController : Controller 
{ 
} 

답변

2

아래 RendererView 클래스입니다. 이러한 백그라운드 스레드에서 외부로 사용할 수 없습니다. 또한 implement recurring background tasks in an ASP.NET applications에게는 나쁜 습관으로 간주됩니다. 권장되는 방법은 웹 응용 프로그램에서이 작업을 오프로드하여 Windows 스케줄러에서 정기적으로 실행되는 Windows 서비스 또는 콘솔 응용 프로그램에 배치하는 것입니다.

그렇다면 권장 된 접근 방식을 따르지 않고 여전히이 방법을 고집하면 using the Razor engine outside of an ASP.NET application을 사용하면 HttpContext에 의존하지 않을 수도 있습니다.

+0

이 경우 Windows 서비스 또는 웹 서비스를 사용해야합니까 –

+2

Windows 서비스에서 전자 메일을 보내야합니다. –

1

HTTP 요청 스레드가 아닌 다른 스레드에서 HttpContext.Current에 액세스 할 수 없기 때문입니다. 컨텍스트를 전달하는 대신 위험 할 수있는 방법은 없습니다.

ASP.NET (예 : Windows 서비스)과 분리 된 코드에서 코드를 실행하는 것이 좋습니다.

+0

Windows 서비스를 사용한다면 어떻게 면도기 뷰에서 전자 메일 템플릿을 만들 수 있습니까? –

+0

ASP.NET없이 Razor 뷰 엔진을 호출하는 데 사용할 수있는 특별한 패키지 인 RazorEngine이 있습니다. 여기 [https://razorengine.codeplex.com/]에서 찾을 수 있습니다. –