{"id":12355,"date":"2018-03-01T10:00:26","date_gmt":"2018-03-01T18:00:26","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=12355"},"modified":"2018-03-01T10:00:26","modified_gmt":"2018-03-01T18:00:26","slug":"asp-net-core-2-1-razor-ui-in-class-libraries","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-2-1-razor-ui-in-class-libraries\/","title":{"rendered":"ASP.NET Core 2.1.0-preview1: Razor UI in class libraries"},"content":{"rendered":"<p>One frequently requested scenario that ASP.NET Core 2.1 improves is building UI in reusable class libraries. With ASP.NET Core 2.1 you can package your Razor views and pages (.cshtml files) along with your controllers, page models, and data models in reusable class libraries that can be packaged and shared. Apps can then include pre-built UI components by referencing these packages and customize the UI by overriding specific views and pages.<\/p>\n<p>To try out building Razor UI in a class library first install the <a href=\"https:\/\/www.microsoft.com\/net\/download\/dotnet-core\/sdk-2.1.300-preview1\">.NET Core SDK for 2.1.0-preview1<\/a>.<\/p>\n<p>Create an ASP.NET Core Web Application by running <code>dotnet new razor<\/code> or selecting the corresponding template in Visual Studio. The default template has fivestandard pages: Home, About, Contact, Error, and Privacy. Let&#8217;s move the Contact page into a class library. Add a .NET Standard class library to the solution and reference it from the ASP.NET Core Web Application.<\/p>\n<p>We need to make some modifications to the class library .csproj file to enable Razor compilation. We need to set the <code>RazorCompileOnBuild<\/code>, <code>IncludeContentInPack<\/code>, and <code>ResolvedRazorCompileToolset<\/code> MSBuild properties as well as add the .cshtml files as content and also a package reference to <a href=\"https:\/\/nuget.org\/packages\/Microsoft.AspNetCore.Mvc\">Microsoft.AspNetCore.Mvc<\/a>. Your class library project file should look like this:<\/p>\n<p><strong>ClassLibrary1.csproj<\/strong><\/p>\n<pre><code class=\"lang-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Project<\/span> <span class=\"hljs-attr\">Sdk<\/span>=<span class=\"hljs-string\">\"Microsoft.NET.Sdk\"<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>netstandard2.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ResolvedRazorCompileToolset<\/span>&gt;<\/span>RazorSdk<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ResolvedRazorCompileToolset<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">RazorCompileOnBuild<\/span>&gt;<\/span>true<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">RazorCompileOnBuild<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">IncludeContentInPack<\/span>&gt;<\/span>false<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">IncludeContentInPack<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Content<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Pages***.cshtml\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Microsoft.AspNetCore.Mvc\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"2.1.0-preview1-final\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Project<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p>For Preview1 making these project file modifications is a manual step, but in future previews we will provide a Razor MSBuild SDK (Microsoft.NET.Sdk.Razor) as well as project templates to handle these details for you.<\/p>\n<p>Now we can add some Razor files to our class library. Add a <code>Pages<\/code> directory to the class library project and move over the Contact page along with its page model (<code>Contact.cshtml<\/code>, <code>Contact.cshtml.cs<\/code>) from the web app project. You&#8217;ll also need to move over <code>_ViewImports.cshtml<\/code> to get the necessary using statements.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/03\/class-lib-with-razor.png\" alt=\"Class library with Razor\" \/><\/p>\n<p>Add some content to the <code>Contact.cshtml<\/code> file so you can tell it&#8217;s being used.<\/p>\n<pre><code class=\"lang-html\"><span class=\"hljs-meta\">@page<\/span>\n<span class=\"hljs-meta\">@model<\/span> ContactModel\n<span class=\"hljs-meta\">@{<\/span>\n    ViewData[<span class=\"hljs-string\">\"Title\"<\/span>] = <span class=\"hljs-string\">\"Contact\"<\/span>;\n}\n<span class=\"hljs-variable\">&lt;h2&gt;<\/span><span class=\"hljs-meta\">@ViewData[\"Title\"]&lt;\/h2&gt;<\/span>\n<span class=\"hljs-variable\">&lt;h3&gt;<\/span><span class=\"hljs-meta\">@Model.Message&lt;\/h3&gt;<\/span>\n\n<span class=\"hljs-variable\">&lt;h2&gt;<\/span>BTW, this is from a Class Library!<span class=\"hljs-variable\">&lt;\/h2&gt;<\/span>\n<\/code><\/pre>\n<p>Run the app and browse to the Contact page.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/03\/contact-page-from-class-lib.png\" alt=\"Contact page from a class library\" \/><\/p>\n<p>You can override views and pages from a class library in your app by putting the page or view at the same path in your app. For example, let&#8217;s add a <code>_Message.cshtml<\/code> partial view that gets called from the contact page.<\/p>\n<p>In the class library project add a <code>Shared<\/code> folder under the <code>Pages<\/code> folder and add the following partial view:<\/p>\n<p><strong>_Message.cshtml<\/strong><\/p>\n<pre><code class=\"lang-html\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>You can override me!<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p>Then call the <code>_Message<\/code> partial from the contact page using the new partial tag helper.<\/p>\n<p><strong>Contact.cshtml<\/strong><\/p>\n<pre><code class=\"lang-html\"><span class=\"hljs-meta\">@page<\/span>\n<span class=\"hljs-meta\">@model<\/span> ContactModel\n<span class=\"hljs-meta\">@{<\/span>\n    ViewData[<span class=\"hljs-string\">\"Title\"<\/span>] = <span class=\"hljs-string\">\"Contact\"<\/span>;\n}\n<span class=\"hljs-variable\">&lt;h2&gt;<\/span><span class=\"hljs-meta\">@ViewData[\"Title\"]&lt;\/h2&gt;<\/span>\n<span class=\"hljs-variable\">&lt;h3&gt;<\/span><span class=\"hljs-meta\">@Model.Message&lt;\/h3&gt;<\/span>\n\n<span class=\"hljs-variable\">&lt;h2&gt;<\/span>BTW, this is from a Class Library!<span class=\"hljs-variable\">&lt;\/h2&gt;<\/span>\n\n<span class=\"hljs-variable\">&lt;partial name=\"_Message\" \/&gt;<\/span>\n<\/code><\/pre>\n<p>Run the app to see that the partial is now rendered.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/03\/contact-page-with-partial.png\" alt=\"Contact page with partial\" \/><\/p>\n<p>Now override the partial by adding a <code>_Message.cshtml<\/code> file to the web app under the <code>\/Pages\/Shared<\/code> folder.<\/p>\n<p><strong>_Message.cshtml<\/strong><\/p>\n<pre><code class=\"lang-html\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Overridden!<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p>Rebuild and run the app to see the update.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/03\/contact-page-with-overridden-partial.png\" alt=\"Overridden partial\" \/><\/p>\n<h3 id=\"summary\">Summary<\/h3>\n<p>By compiling Razor views and pages into shareable libraries you can reuse existing UI with minimal effort. Please give this feature a try and let us know what you think on <a href=\"https:\/\/github.com\/aspnet\/razor\/issues\">GitHub<\/a>. Thanks!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One frequently requested scenario that ASP.NET Core 2.1 improves is building UI in reusable class libraries. With ASP.NET Core 2.1 you can package your Razor views and pages (.cshtml files) along with your controllers, page models, and data models in reusable class libraries that can be packaged and shared. Apps can then include pre-built UI [&hellip;]<\/p>\n","protected":false},"author":417,"featured_media":21391,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509],"tags":[7542,7547,7384,7548],"class_list":["post-12355","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-asp-net-core-2-1-0-preview1","tag-libraries","tag-razor","tag-ui"],"acf":[],"blog_post_summary":"<p>One frequently requested scenario that ASP.NET Core 2.1 improves is building UI in reusable class libraries. With ASP.NET Core 2.1 you can package your Razor views and pages (.cshtml files) along with your controllers, page models, and data models in reusable class libraries that can be packaged and shared. Apps can then include pre-built UI [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/12355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/417"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=12355"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/12355\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21391"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=12355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=12355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=12355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}