【问题标题】:Implement MVC ViewRenderer in a .NET console application在 .NET 控制台应用程序中实现 MVC ViewRenderer
【发布时间】:2017-11-19 16:36:54
【问题描述】:

我在我的 MVC 5 项目中添加了一个时事通讯功能,用于向所有订阅用户发送构建的邮件。
我有一个类,public async Task<NewsletterLogResult> SendNewsletters(int? id = null, ControllerContext ControllerContext = null) 被一个动作调用 public async Task<ActionResult>SendMail(int id)
SendNewsletters 实现 Viewrenderer,类似这样的 cBody = ViewRenderer.RenderPartialView(ViewRenderer.TemplatePath + "Newsletters/" + record.Newsletter_Template + "Body.cshtml", record, ControllerContext);

public class ViewRenderer
{
    protected ControllerContext Context { get; set; }

    public const string TemplatePath = "~/Views/Templates/";

    public ViewRenderer(ControllerContext controllerContext = null)
    {
        // Create a known controller from HttpContext if no context is passed
        if (controllerContext == null)
        {
            if (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;
    }

    public string RenderViewToString(string viewPath, object model = null)
    {
        return RenderViewToStringInternal(viewPath, model, false);
    }

    public void RenderView(string viewPath, object model, TextWriter writer)
    {
        RenderViewToWriterInternal(viewPath, writer, model, false);
    }

    public string RenderPartialViewToString(string viewPath, object model = null)
    {
        return RenderViewToStringInternal(viewPath, model, true);
    }

    public void RenderPartialView(string viewPath, object model, TextWriter writer)
    {
        RenderViewToWriterInternal(viewPath, writer, model, true);
    }

    public static string RenderView(string viewPath, object model = null,
                                    ControllerContext controllerContext = null)
    {
        ViewRenderer renderer = new ViewRenderer(controllerContext);
        return renderer.RenderViewToString(viewPath, model);
    }

    public static void RenderView(string viewPath, TextWriter writer, object model,
                                    ControllerContext controllerContext)
    {
        ViewRenderer renderer = new ViewRenderer(controllerContext);
        renderer.RenderView(viewPath, model, writer);
    }

    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;
    }

    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;
        }
    }

    public static string RenderPartialView(string viewPath, object model = null,
                                            ControllerContext controllerContext = null)
    {
        ViewRenderer renderer = new ViewRenderer(controllerContext);
        return renderer.RenderPartialViewToString(viewPath, model);
    }

    public static void RenderPartialView(string viewPath, TextWriter writer, object model = null,
                                            ControllerContext controllerContext = null)
    {
        ViewRenderer renderer = new ViewRenderer(controllerContext);
        renderer.RenderPartialView(viewPath, model, writer);
    }

    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);
    }

    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);
            throw new Exception("Can't find view.");
        }

        // 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;
    }

    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 (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;
    }

}

public class EmptyController : Controller
{
}

这在 MVC 中完美运行。
就像从 Web 应用程序运行时事通讯发送任务不是一个好习惯一样,我想在 Windows 服务中实现此功能。为了方便我在 Consoleapp 中进行测试,从这里调用 SendNewsletters。 但是在 Consolapp 中,就像在 WIndowsService 中一样,我没有 HttpContext,因此,可以创建一个假 HttpContext,最好能够访问 MVC 路由(我的 razor 视图实现了路由助手,url.action) ?

【问题讨论】:

  • 你能试试在 MVC 应用程序上工作的 Quartz.NET JobScheduler

标签: c# .net asp.net-mvc razor console


【解决方案1】:

我解决了这个问题存储在数据库中,另外,viewrendered的结果。此信息在 MVC 应用程序中处理,因此我不需要 HttpContext 或任何路由。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多