你好,我想在特定时间发送电子邮件,我找到了代码。
在global.asax.cs文件上
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发送电子邮件,并且在正文中,我将部分 View 呈现为字符串类,以将我的 Razor View 呈现为字符串
string body = ViewRenderer.RenderPartialView("~/Views/Shared/Email.cshtml", LEM);
问题是它没有得到HttpContext.Current.It显示HttpContext.Current = null。我认为两者都在创建Thread,因此这就是为什么它没有获得HttpContext的原因,所以我怎么能在同一个httpcontext中使用两者。
这是下面的RendererView类
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
{
}
最佳答案
HttpContext
仅在HTTP请求的生存期内可用。在此类后台线程中无法在外部使用它。另外,将 implement recurring background tasks in an ASP.NET applications
视为不良做法。推荐的方法是从Web应用程序中卸载此任务,并将其放入Windows服务或控制台应用程序中,这些任务将由Windows Scheduler定期执行。
话虽如此,如果您决定不遵循建议的方法而仍然坚持这样做,则可以考虑使用 using the Razor engine outside of an ASP.NET application
,这样您就不必依赖HttpContext
了。
关于c# - 带有HttpContext的Thread.Timer无法正常工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41760705/