{"action":"created","issue":{"url":"https://api.github.com/repos/aspnet/Mvc/issues/3091","repository_url":"https://api.github.com/repos/aspnet/Mvc","labels_url":"https://api.github.com/repos/aspnet/Mvc/issues/3091/labels{/name}","comments_url":"https://api.github.com/repos/aspnet/Mvc/issues/3091/comments","events_url":"https://api.github.com/repos/aspnet/Mvc/issues/3091/events","html_url":"https://github.com/aspnet/Mvc/issues/3091","id":104820768,"number":3091,"title":"Guidance on how, or a 'friendlier' way, to render views to strings (for emails, service calls, etc.)","user":{"login":"tuespetre","id":4853540,"avatar_url":"https://avatars.githubusercontent.com/u/4853540?v=3","gravatar_id":"","url":"https://api.github.com/users/tuespetre","html_url":"https://github.com/tuespetre","followers_url":"https://api.github.com/users/tuespetre/followers","following_url":"https://api.github.com/users/tuespetre/following{/other_user}","gists_url":"https://api.github.com/users/tuespetre/gists{/gist_id}","starred_url":"https://api.github.com/users/tuespetre/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tuespetre/subscriptions","organizations_url":"https://api.github.com/users/tuespetre/orgs","repos_url":"https://api.github.com/users/tuespetre/repos","events_url":"https://api.github.com/users/tuespetre/events{/privacy}","received_events_url":"https://api.github.com/users/tuespetre/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/aspnet/Mvc/labels/3%20-%20Done","name":"3 - Done","color":"CCCCCC"},{"url":"https://api.github.com/repos/aspnet/Mvc/labels/discussion","name":"discussion","color":"5319e7"}],"state":"closed","locked":false,"assignee":{"login":"ajaybhargavb","id":1579269,"avatar_url":"https://avatars.githubusercontent.com/u/1579269?v=3","gravatar_id":"","url":"https://api.github.com/users/ajaybhargavb","html_url":"https://github.com/ajaybhargavb","followers_url":"https://api.github.com/users/ajaybhargavb/followers","following_url":"https://api.github.com/users/ajaybhargavb/following{/other_user}","gists_url":"https://api.github.com/users/ajaybhargavb/gists{/gist_id}","starred_url":"https://api.github.com/users/ajaybhargavb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ajaybhargavb/subscriptions","organizations_url":"https://api.github.com/users/ajaybhargavb/orgs","repos_url":"https://api.github.com/users/ajaybhargavb/repos","events_url":"https://api.github.com/users/ajaybhargavb/events{/privacy}","received_events_url":"https://api.github.com/users/ajaybhargavb/received_events","type":"User","site_admin":false},"assignees":[{"login":"ajaybhargavb","id":1579269,"avatar_url":"https://avatars.githubusercontent.com/u/1579269?v=3","gravatar_id":"","url":"https://api.github.com/users/ajaybhargavb","html_url":"https://github.com/ajaybhargavb","followers_url":"https://api.github.com/users/ajaybhargavb/followers","following_url":"https://api.github.com/users/ajaybhargavb/following{/other_user}","gists_url":"https://api.github.com/users/ajaybhargavb/gists{/gist_id}","starred_url":"https://api.github.com/users/ajaybhargavb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ajaybhargavb/subscriptions","organizations_url":"https://api.github.com/users/ajaybhargavb/orgs","repos_url":"https://api.github.com/users/ajaybhargavb/repos","events_url":"https://api.github.com/users/ajaybhargavb/events{/privacy}","received_events_url":"https://api.github.com/users/ajaybhargavb/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/aspnet/Mvc/milestones/20","html_url":"https://github.com/aspnet/Mvc/milestones/1.0.0-rc2","labels_url":"https://api.github.com/repos/aspnet/Mvc/milestones/20/labels","id":1370810,"number":20,"title":"1.0.0-rc2","description":"","creator":{"login":"Eilon","id":202643,"avatar_url":"https://avatars.githubusercontent.com/u/202643?v=3","gravatar_id":"","url":"https://api.github.com/users/Eilon","html_url":"https://github.com/Eilon","followers_url":"https://api.github.com/users/Eilon/followers","following_url":"https://api.github.com/users/Eilon/following{/other_user}","gists_url":"https://api.github.com/users/Eilon/gists{/gist_id}","starred_url":"https://api.github.com/users/Eilon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Eilon/subscriptions","organizations_url":"https://api.github.com/users/Eilon/orgs","repos_url":"https://api.github.com/users/Eilon/repos","events_url":"https://api.github.com/users/Eilon/events{/privacy}","received_events_url":"https://api.github.com/users/Eilon/received_events","type":"User","site_admin":false},"open_issues":0,"closed_issues":228,"state":"closed","created_at":"2015-10-22T16:51:50Z","updated_at":"2016-05-20T21:19:53Z","due_on":null,"closed_at":"2016-05-20T21:19:53Z"},"comments":20,"created_at":"2015-09-04T02:50:27Z","updated_at":"2016-10-08T18:29:55Z","closed_at":"2016-02-26T18:00:08Z","body":"There are a handful of libraries and snippets floating around out there for how to render a view to a string for use as an email's body or for some other purpose (maybe submitting content to another service, for instance.) \r\n\r\nWould the team consider adding some form of 'official' convenient way of satisfying these use cases? There just seems to be a lot of weirdness around the current methods out there, and I would think those use cases are very common, whether needed by beginner or advanced developers.\r\n\r\nI could see asking developers to depend on the `IViewEngine` interface (or the `ICompositeViewEngine` interface as it stands, although I feel `IViewEngine` is a little more obvious/expected :stuck_out_tongue:) in order to obtain the view they wish to render, but when it comes to actually rendering the view, I can't imagine most cases needing more than the simple ability to be able to **take an `IView` instance, pass in a an `object`, and get a `string` out.**\r\n\r\n### Resources\r\n\r\n- https://github.com/aspnet/Mvc/issues/2871\r\n\r\n  Discusses rendering views to strings, but revolves around dependency injection\r\n  and service location rather than encapsulation\r\n\r\n- http://stackoverflow.com/questions/31905624/where-are-the-controllercontext-and-viewengines-properties-in-mvc-6-controller\r\n\r\n  Recent example for MVC 6\r\n\r\n- http://aboutcode.net/postal/\r\n\r\n  A popular library that deals some, but not all, of the mailing use cases (in cases I've used, I've still had to do some `HttpContext` rigging and jigging)\r\n\r\n### My own working example for MVC6 (using the nightly feed)\r\n\r\nThis class is registered as a scoped service in Startup. As you can see, there is little in the way of error handling or flexibility. A proper, 'friendly' API could have more public methods for different use cases, and some kind of 'result' class (similar to `ViewEngineResult`.)\r\n\r\n`RazorHelper.cs`\r\n```\r\nusing Microsoft.AspNet.Http;\r\nusing Microsoft.AspNet.Mvc;\r\nusing Microsoft.AspNet.Mvc.Actions;\r\nusing Microsoft.AspNet.Mvc.ModelBinding;\r\nusing Microsoft.AspNet.Mvc.Rendering;\r\nusing System.IO;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace Checkout.AspNet5.Services\r\n{\r\n    public class RazorHelper\r\n    {\r\n        private IHttpContextAccessor httpContextAccessor;\r\n        private IActionContextAccessor actionContextAccessor;\r\n        private ICompositeViewEngine viewEngine;\r\n        private ITempDataProvider tempDataProvider;\r\n\r\n        public RazorHelper(\r\n            IHttpContextAccessor httpContextAccessor,\r\n            IActionContextAccessor actionContextAccessor,\r\n            ICompositeViewEngine viewEngine,\r\n            ITempDataProvider tempDataProvider)\r\n        {\r\n            this.httpContextAccessor = httpContextAccessor;\r\n            this.actionContextAccessor = actionContextAccessor;\r\n            this.viewEngine = viewEngine;\r\n            this.tempDataProvider = tempDataProvider;\r\n        }\r\n\r\n        public async Task<string> RenderView<TModel>(string name, TModel model, bool partial = true)\r\n        {\r\n            var actionContext = actionContextAccessor.ActionContext;\r\n\r\n            var viewEngineResult = partial \r\n                ? viewEngine.FindPartialView(actionContext, name)\r\n                : viewEngine.FindView(actionContext, name);\r\n\r\n            using (var output = new StringWriter())\r\n            {\r\n                var view = viewEngineResult.View;\r\n                var viewContext = new ViewContext(\r\n                    actionContext,\r\n                    viewEngineResult.View,\r\n                    new ViewDataDictionary<TModel>(\r\n                        metadataProvider: new EmptyModelMetadataProvider(),\r\n                        modelState: new ModelStateDictionary())\r\n                    {\r\n                        Model = model\r\n                    },\r\n                    new TempDataDictionary(\r\n                        httpContextAccessor,\r\n                        tempDataProvider),\r\n                    output,\r\n                    new HtmlHelperOptions());\r\n\r\n                await view.RenderAsync(viewContext);\r\n\r\n                return output.ToString();\r\n            }\r\n        }\r\n    }\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/aspnet/Mvc/issues/comments/252440463","html_url":"https://github.com/aspnet/Mvc/issues/3091#issuecomment-252440463","issue_url":"https://api.github.com/repos/aspnet/Mvc/issues/3091","id":252440463,"user":{"login":"mythz","id":89361,"avatar_url":"https://avatars.githubusercontent.com/u/89361?v=3","gravatar_id":"","url":"https://api.github.com/users/mythz","html_url":"https://github.com/mythz","followers_url":"https://api.github.com/users/mythz/followers","following_url":"https://api.github.com/users/mythz/following{/other_user}","gists_url":"https://api.github.com/users/mythz/gists{/gist_id}","starred_url":"https://api.github.com/users/mythz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mythz/subscriptions","organizations_url":"https://api.github.com/users/mythz/orgs","repos_url":"https://api.github.com/users/mythz/repos","events_url":"https://api.github.com/users/mythz/events{/privacy}","received_events_url":"https://api.github.com/users/mythz/received_events","type":"User","site_admin":false},"created_at":"2016-10-08T18:29:54Z","updated_at":"2016-10-08T18:29:54Z","body":"Is there anyway to change which Layout a View uses at runtime when rendering to string?"}}
{"actor":{"display_login":"mythz"}}