ASP.NET Core 2.1 introduces Razor Class Library (RCL). It’s the new way how to share reusable web application components with UI as dependent project or NuGet package. As public examples mostly cover how it works with Razor Pages, I decided to write this blog post and demo application for ASP.NET Core MVC.
Source code available! I created demo application that shows all stuff written here. Feel free to visit my GitHub repository gpeipman/RazorClassLibraryDemo. To make it work it’s important to have stable release of .NET Core 2.1 without any preview or release candidate releases.
What is Razor Class Library?
Razor Class Library is ASP.NET Core library that contains pages, views, view components and other web application artifacts with their respective code. Library doesn’t run independent – there must be application that includes library and uses its functionalities. Razor class libraries make it easy to share web applications code with UI elements.
Razor class libraries doesn’t work well on preview and release candidate versions of ASP.NET Core 2.1.
Screenshot on right shows default structure. For some reason the project comes with Razor page. There is nothing about MVC and there’s also no project template for Razor class library with MVC structure.
But MVC is actually supported and it’s up to us to build the project structure we need.
Referencing Razor class library
There are two ways to reference Razor class library:
- Project reference
- NuGet package
If class library is in same solution with web application then project reference is enough.
Another important dependency is project dependency under build dependencies menu (right click on web application and select Build dependencies).
Setting this dependency tells Visual Studio that library project must be built before web application one.
Moving to MVC
There are some things to know:
- Controllers must have AreaAttribute
- Web application must have area route defined
Now let’s implement these changes and let’s make things work.
We start with HomeController in library project. I started with minimal and extremely primitive code.
public class HomeController : Controller
public IActionResult Index()
Same goes for Index view of HomeController.
<h1>Hello from MyFeature</h1>
In Startup class of web application include MVC like show here (Configure method).
Now we are ready to run our application and try out view from Razor class library.
Hold on, what the hell is this? Well… we have area defined in another project and what’s going on in web application doesn’t apply to it fully. We need to copy _ViewStart.cshtml file under Shared folder in Razor class library. After this things get better.
This is the easiest method to use and it works well for applications with only one layout.
Overriding Razor class library views
It’s possible we want to use our own view instead of one that comes with Razor classlibrary.
It’s possible to override also controllers the same way but this is more complex topic and it needs some good analyzis before doing so. The question comes down to simple thing – is library author expecting something like this to happen?
Image on right shows how I replicated areas structure in Razor class library above to web application. Notice how there is only the index view of HomeController that I want to override.
Here is the primitive content of overriden view.
<h1>Hello from overridden MyFeature</h1>
And here is our overridden view in action.
If needed we can override views but we have to be careful – views from Razor class library may contain logic we don’t know.
Razor Class Library is excellent way how to share web application components and UI artifacts. It’s not just about sharing components between projects in same solution – we can share our Razor class libraries as NuGet packages. The model seems flexible enough for me as it easy to take risks of overriding controllers, models, views and other components. I don’t give any suggestion right now about overriding as I am not yet sure what weight it actually puts to those responsible of Razor class libraries. Anyway, with Razor class libraries one problem is solved again.