Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to use Razor in a console application

I know similar questions have been asked before, but the only answers are six years old, and the projects people refer to seem like they're not being maintained.

I want to use Razor in a console app or a class library to render HTML. I would also like to have working Intellisense in the .cshtml files.

Currently, I am able to jury-rig this by doing the following:

  • Create console app.
  • Add .cshtml file.
  • In Properties, set the Custom Tool property to RazorTemplatePreprocessor

This causes Razor syntax to be recognized. So if you have Test.cshtml, it generates a class called Test that you can use like so:

var test = new Test();
test.Model = "Hi there";
var html = test.GenerateString();

Console.WriteLine(html);

This is just about good enough for my purposes. However, the actual coding experience within the .cshtml file is pretty broken:

  • There are red squigglies all over the place complaining about:
  • Not being able to use var because it's C# 2.
  • Saying the type or namespace of various types can't be found.
  • The above is especially true of types imported from other libraries.
  • The @model keyword is not recognized.
  • Intellisense sometimes works, sometimes doesn't.

Weirdly, if you just ignore all of these errors, the HTML is actually generated correctly, including use of the libraries and @model keyword that the Razor engine complained about. However, this causes major mental clutter because if you have any number of .cshtml files, you very quickly get into hundreds and thousands of these errors mixed in with real errors.

Is there anything I can do to cause the actual Razor coding experience to work more like it does in an ASP.NET web app?

like image 943
Brian Rak Avatar asked Apr 28 '18 19:04

Brian Rak


People also ask

What is console application in C sharp?

A console application, in the context of C#, is an application that takes input and displays output at a command line console with access to three basic data streams: standard input, standard output and standard error.

Is Cshtml a Razor?

cshtml files are razorpages or MVC views, they does not contain any C#-written client-side code. If you wan to do so, you must use JavaScript. However, a . razor file, also know as a Razor component, can have C# written in it and run on client's browser.


1 Answers

I have been working on this sporadically since I asked the question nearly two years ago, and I believe I have a 99% non-clunky solution. Everything below works for me in Visual Studio 16.4.5.

Here's what I have learned about getting Razor to work in console and library projects.

  1. Everything seems to work with the least trouble if create and consume your Razor files in a .NET Core console app.
  2. You can also put your Razor files in a .NET Standard library and consume them from a .NET Core console app, though in this case there is some minor ugliness in Solution Explorer. I don't think it has any effect on functionality, however.
  3. Either way, both the @model and the @using keywords work correctly, Intellisense works correctly, lambda expressions work correctly, everything seems to work properly.

Here's what you have to do:

To add a Razor file:

Add a new HTML file, but name the file with a .cshtml extension.

Select the file in Solution Explorer. In the Properties window, under Custom Tool, enter RazorTemplatePreprocessor. A .cs file will immediately be generated.

To consume the generated class:

var razor = new MyRazorClass();
razor.Model = "Hello from Razor";       // Assumes @model string in the Razor file; custom classes are fine too.
var html = razor.GenerateString();
Console.WriteLine(html);

To resolve the errors in the Error List (which incidentally do not seem to affect functionality but certainly create mental clutter):

Add NuGet references to:

Microsoft.AspNetCore.Mvc.Core
Microsoft.AspNetCore.Mvc.Razor

If you are adding your Razor files to a .NET Standard library, you'll get a bunch of the following errors:

Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.

To fix this, add the following two lines to the project file:

<PropertyGroup>
  <TargetFramework>netstandard2.0</TargetFramework>
  <Nullable>enable</Nullable>                         <!-- Add this line -->
  <LangVersion>8.0</LangVersion>                      <!-- Add this line -->
</PropertyGroup>

At this point, the project should compile with no errors or warnings!

However, it doesn't work perfectly. There some oddities, which give me some concern that things might unexpectedly break on me in the future.

These problems only seem to occur when using Razor files from .NET Standard libraries:

  1. The Solution Explorer sometimes shows the descendants of the .cshtml file in two different ways:

a. In what I believe is the correct way, the .cshtml file has as its only descendant a generated .cs file. That file in turn has two generated classes, YourRazorClass and YourRazorClassBase. Each of those can be expanded to show the class members, which have nice, human-readable names.

b. Sometimes, however, an underscore-prefixed class appears as a direct descendant of the .cshtml file (e.g., _MyTestRazorClass), Also, its class members are different.

This seems to appear and disappear from the Solution Explorer and I don't think it causes any harm, but it certainly causes some mental clutter as you wonder what on earth is going on.

  1. In Solution Explorer, under the [Project Name] > Dependencies > Analyzers, there are a bunch of warnings that get propagated up into the same section of any project that consumes the library. This also creates mental clutter. Fortunately, you can turn these off by doing the following:

a. Right-click the project and choose Properties. b. Under Code Analysis, uncheck the Run on Build and Run on Live Analysis boxes.

One final note: I have not yet tested using a .NET Standard library set up in this way inside a Xamarin project yet (this is the scenario that originally had me going down this road), but I will do so in the future and update this answer at that time.

UPDATE: I have now used this technique in a released Xamarin app! The only weirdness is that you can't copy-paste .cshtml files to create a new one. It screws up both the original file and the copy and you have to go edit the project file to fix things. Instead, just manually add a new file as described above each time.

I hope this helps someone. And if anyone figures out what is going on with the weirdness in Solution Explorer, I would love to know!

like image 166
Brian Rak Avatar answered Sep 20 '22 12:09

Brian Rak