在.NET控制台应用程序中实现MVC ViewRenderer

时间:2017-11-19 16:36:54

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

我在我的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视图实现了路由助手,{{1} })?

1 个答案:

答案 0 :(得分:0)

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