Browsed by
Category: .NET Core

HTML Formatting in .NET Resource Strings

HTML Formatting in .NET Resource Strings

Whilst working on a client website, and I was adding content to the page based on the provided mockups and designs. All was going fine except for one part – a few paragraphs of content had formatting in the middle. Some had bold words, some had links etc.
This was a problem because I was storing all content in resource strings to allow for easier localisation.
One solution is to split the content into multiple parts, and you can apply the formatting around that, but I don’t think that’s ideal.
While it removes any html code from the content if you get it translated, I find it can also lead to a lack of context so you might not get the translation you’re after.
I also find it quite messy having to place multiple strings together around the formatting on the View, much easier to just have one string.

A (fairly quick) search around the net didn’t reveal the solution, but got me half way there. So I thought I’d quickly document the steps needed to be able to use the resource strings, and still have HTML formatting applied.

For a simple example, the string I might be trying to use could be:
Hello, my name is <strong>Ian Rufus</strong> and I love .NET!  and be in my resources under the name MyContentString
Firstly, when writing the content on the View, don’t just use the string with @Strings.MyContentString
Instead, use @Html.Raw(@Strings.MyContentString) which allows us to render unencoded HTML.

This alone won’t get any formatting applied, we also require a basic change to the resource string.
Instead of the <strong>Ian Rufus</strong>
part of the content string I’m using, we need to replace the angular brackets with the HTML code for that symbol, which is &lt; for < and &gt; for >.
This will give you the full string as Hello, my name is <strong>Ian Rufus</strong> and I love .NET!
This site is a great resource for finding the HTML codes you’ll be after.

And that’s it. The combination of using @Html.Raw() and using HTML codes in the resource string are all you need, and formatting will now be displayed correctly on the View.

Hope that’s helpful!

Rendering Emails with RazorViewEngine in .NET Core 2.0

Rendering Emails with RazorViewEngine in .NET Core 2.0

In this post I’m going to cover how to use the RazorViewEngine to render Views, and get the string content so it can be used as an email template.
As always, the code for this example can be found on Github here.

This has been done in .NET Core 2.0, and I’ve created this on my Mac – though being .NET Core it works equally well on Windows (tested on my Surface Pro), and in theory should on Linux too.

To start with I created a Web API and Console project using the dotnet cli. And given this was done through the cli, I then created a solution and added the two projects to it the same way.
In the code for the API I modified the Program class to set a specific port – 5020. This is just so that it launches on the same port when I run the code, so my Console app knows where to send requests.
It’s worth noting here that if you’re running this through Visual Studio you will have to set the port on the project setting as Visual Studio overrides the setting.

The first thing to do is set up a controller for us to talk to. By default the API comes with a ‘Values’ controller, so I’ve renamed that to ‘Email’, removed the boilerplate code, and added a simple Get method that, for now, just returns a hard coded string:

I’ve then set up the Console to send a request to this endpoint, printing out the result. This is just so we can easily see what’s being output:

Now if you run both applications, you can see simply that “hello” gets printed to the console whenever we press enter.
The next step is to start setting up our API for the rendering. I’ve created a ‘Templating’ folder in the API, and a subfolder called ‘Emails’. In the Emails folder I’ve added one .cshtml file called HelloEmail.cshtml which is blank for now.
Create a class under the ‘Templating’ folder called RazorViewToStringRenderer. The purpose of this class is going to be to find an IView through the RazorViewEngine, and render that by calling RenderAsync.
The RenderAsync method takes in a ViewContext parameter. So the first thing we need to do is create the ViewContext – which means we need the parameters.
The first parameter is an ActionContext. I’ve added a private method to generate this which simply sets up a HttpContext, and uses that to create the ActionContext:

As you can see I’ve used a field called _serviceProvider, which is an implementation of IServiceProvider, that we don’t have yet, so let’s add that at the top of the class. We’re also going to make use of two other fields – ITempDataProvider and IRazorViewEngine:

The TempDataProvider is needed for the ViewContext later, and the RazorViewEngine is what will help find and render our Views.
These fields will need setting, so let’s create a constructor for this class passing in the three interfaces, and setting the fields:

Now we need a method that’s going to make use of GetActionContext, as well as handling the rest of the operation, so add an async method (RenderAsync, remember!) that takes in the name of the View we want, and the type of the model for the View – TModel so this can be used for any and all Views.
In here we can call to create our ActionContext, and make use of the defined RazorViewEngine, and the view name parameter, to locate our View. After the call to locate the View, I’ve checked the Success property to check the View was actually found. The method should look like this for now:

As you can see we get our ActionContext, and use that and the passed in name variable to locate the View through the RazorViewEngine. If successful we get the View from the result, otherwise we throw an exception – obviously what you do in this scenario is up to you!

Now we have the View, we need to create the ViewContext. As mentioned, the first parameter is the ActionContext that we already have. The remaining parameters are the View, a ViewDataDictionary, a TempDataDictionary, a TextWriter, and HtmlHelperOptions.
So to create the ViewContext we pass in the ActionContext and View objets we already have, then we can create the remaining parameters – we instantiate a ViewDataDictionary of type TModel, with new instances of both parameters, and set the Model property to our passed in model.
Next is the TempDataDictionary which we create by passing in the HttpContext of our ActionContext, and our _tempDataProvider field.
For the TextWriter, I’ve added a using statement for a StringWriter, and placed the creation of the ViewContext in there – then I can used the defined StringWriter for the parameter.
Lastly, pass in a new instance of HtmlHelperOptions:

Now that we have both our View, and the ViewContext, we can simply call the RenderAsync method, and get the string output. Inside the using statement, after the creation of the ViewContext, we want to add the following lines:

This method will now render our View with the provided model, and return us the string representation of that!
We’ve passed in three parameters to this class, and we don’t want to worry about handling the setup of those objects, so we can use dependency injection to do the heavy lifting.
We want to add an interface for this class, so I created an IViewToStrinRenderer interface, and had the class implement that. The interface simply defines the one method we’ve already implemented:

Now we can configure the startup to register this interface and implementation in the AddServices method:

.NET will do the rest for us!
Now we need the controller we previously set up to make use of this class. I’ve added a constructor to the EmailController class passing in IViewToStringRenderer, and setting this to a private field on the class. Once again, .NET handles injecting this into the controller, which should now start with this:

In order to test this, we’re going to need our templates to do something.
I’ve created a simple HelloEmailModel class, which just contains a Name property so we can see our model binding working. Then for the HelloEmail view, I’ve just set the model, and added a binding to the Name property:

Back in the EmailController, I’m going to hard code in some values, as it’s not important for this demo.
I’ve created an instance of the Model, and set my name. Then I’ve added a try-catch block, which makes use of the RazorViewToStringRenderer to try and make use of our HelloEmail template.
If an exception is thrown (which I added earlier if the view wasn’t found) we return an error message instead:

Great, let’s give it a run and see what happens…

Oh no! We’ve got an error instead.
Error: One or more errors occurred. (Couldn’t find view ‘HelloEmail’)

So RazorViewEngine can’t find the correct .cshtml file, let’s put a breakpoint in and see what’s happened.
We can see that the result’s Success indicator is false. Because of this, there is another property available to us – SearchedLocations. This tells us where the engine has tried to locate our view:

We can see that it’s searched the conventional folders for the templates, but that’s not where I’ve placed them. You could place the template there, but I like to keep things separated more – especially if you intend for your API to actually have some Views.
So now we need to tell the engine to look in the correct location. To do this, we need to add a ViewLocationExpander.
Under the Templating folder create a new class called ViewLocationExpander. This class will implement the IViewLocationExpander.
Implementing the interface gives us two methods we need to populate – ExpandViewLocations and PopulateValues.
I’ve added a list of strings which gets populated in the constructor – this is populated by getting the current directory, and finding all ‘Emails’ folders in there.
Then in the ExpandViewLocations we Union our list, with the passed in list of ViewLocations – if you don’t want to search the default locations, just return your own list.
For PopulateValues we’re just adding a customviewlocation value to the context, for the name of our expander.

In order to make use of the expander, we need to configure the RazorViewEngine to make use of it.
In the Startup, we need to configure the RazorViewEngineOptions to add our expander to the ViewLocationExpanders on the options.

If you run it now you’ll see…. An error still!
Putting a break point in again will show that we have indeed searched an extra location, but it doesn’t look quite right:

For one, that’s an absolute path, which we don’t want as RazorViewEngine works with absolute paths. And you’ll also notice that it’s searched the folder, but not for the view we’re after. We can make a minor change to the ViewLocationExpander to fix this.
We want to remove the root path from each found location, and also append the file name, which can be done with a couple of select statements:

If we run this now, we’ll see that the email has been rendered with our model, hooray!

Let’s make a useful addition – if you have multiple different emails you’ll be managing, you don’t want to be maintaining all the layouts separately. It’s nice to have a consistent theme applied for you – so let’s add a layout file.
Under the Emails folder, add a _Layout.cshtml file.
I’m not going into the details of formatting etc, just enough to show working with layouts works.
In the layout I’m just setting the structure of the page, adding a title, and rendering our body content:

Now if you run the app, you can see our layout is rendered as well as our View. The same works for rendering sections for scripts, content etc – just be careful about what your email client will allow!

There are two small things we want to do now – to make sure things run as expected when we deploy.
The first, is to ensure that the email templates are copied to the output directory – they can be found in the source folder now, but they need to be present when you publish and deploy.
Add the following to your project file:

The second is to improve how we find the templates. The current idea works well enough, but what if you run the project from outside of it’s root folder? If you do so, and have another project containing views present, you can run into rendering issues due to confusion between views with the same name, or with different layout files being found.
To fix this, we pass in the content root path of the hosting environment, and filter out files that don’t match. Inject IHostingEnvironment into your startup, and store the content root in a field, then pass this to the expander. In the expander constructor, we want to only find files that contain that path:

Now you can use the RazorViewEngine to render a View, and get the string content to be used for an email.

One last thing to mention is a potential issue when running integration tests. If you were to add a test using the renderer, you may see a lot of confusing errors about missing references in the View files. A workaround that worked for me is mentioned in this Github issue: https://github.com/aspnet/Razor/issues/1212
It’s just a case of creating one file, and adding a few lines to your project file. Making those changes and the errors went away for me 🙂

As always, please comment, raise an issue on Github, or otherwise get in touch if you see any problems or improvements!

Give your Web API some Swagger with Swashbuckle

Give your Web API some Swagger with Swashbuckle

At work I’m currently working on my very first Web API using .NET Core. As part of this, we wanted to set it up to follow the OpenAPI specification, and provide a tool for other developers here to quickly find out more about the API and test some basic use cases.
Swagger seemed like a good answer to all this, and fortunately there’s even a ready to go implementation for .NET called Swashbuckle. In this post I’ll cover the basics to get up and running with Swashbuckle on a Web API.

I’m going to use a new, default Web API project for this, but it’s easy enough to add this to your existing work, as you’ll see.

First, we need to add Swashbuckle to our project. Open the nuget package manager, ensure you’re including pre-release packages, and find Swashbuckle. At the time of writing this, the latest stable version of Swashbuckle doesn’t support .NET Core, and so you’ll need the latest pre-release version until this goes live. At writing, the latest version is v6.0.0-beta902.
One of the good things about Swashbuckle is that it’s open source, you can find the new repo here. They’ve started from scratch to support .NET Core, so if you do encounter any issues, you can get involved and help resolve the issues yourself 🙂

Now that we have Swashbuckle, it needs to be configured so we can actually make use of it. To do this, go to Startup.cs, and in your ConfigureServices method add:

and in your Configure method add the following:

And that’s it.
If you now run the project, and go to /swagger/ui, you’ll see the name of your controller(s), I see ‘Values’. Clicking on that expands out a list of all the endpoints available, nicely colour coded based on what they do!

Initial setup of Swagger
Initial setup of Swagger

So let’s customize it a bit. First, it would be good to give some more detail to anyone viewing your API.
We’ll add some basic details of the API, and who to contact. To do this, go back to your ConfigureServices method in Startup.cs, and add a call to ConfigureSwaggerGen on the services. In here, we want to create a new SingleApiVersion on the options, setting the desired values:

As you can see, I’ve set a version, a title of the API and it’s description, as well as my contact details so people can shout at me for anything stupid I’ve done.

If you run it again and navigate to /swagger/ui, you’ll immediately see those details.

API details displayed in Swagger
API details displayed in Swagger

The next thing we’ll want to do is add a bit more information to some of our endpoints. We can do that using XML Comments in our code.
First, on your project properties, under build, check the box for ‘XML documentation file’
Now Swashbuckle can make use of the XML comments, so let’s add some to our controller. I’m going to modify the post method, simply adding a few example return types:

We now just need to make Swashbuckle include these comments, so we do that once again in Startup.cs, in our call to ConfigureSwaggerGen, add this to the options:

And the using statement for PlatformServices:

The name of the XML file will depend on your project name, and can be found in your debug folder. This code simple finds the file, and passes the address through to the Swagger options.

If you run the code and once again navigate to swagger, open your method, you’ll see our response messages

XML response codes displayed in Swagger
XML response codes displayed in Swagger

Now run and go to /swagger/ui again, check the method and see the snazzy new response codes!

Another useful thing to do, when accepting a complex object as a parameter, is to have a sample model set up for swagger to use. If you’re adding validation to your model, it saves users worrying about it so much if they can just click the sample and have that sent through.

So first, we’ll need an example class set up, this is the one I created, imaginatively called ExampleModel:

I’ve added a Regular Expression annotation to the email, just to give an example of when a sample model would be of use. Not having a sample model gives the value ‘string’ for all strings, which leaves your default value invalid. Adding a sample model avoids this.
So now we have a model, we need to create a SchemaFilter class. This class will implement SwaggerGen’s ISchemaFilter interface.
Implement the interface, and in the Apply method we want to check that the type matches our class, and if so, set the schema example to an instance of our class:

Now there are two ways of registering this, one is to add the filter as an attribute to your model class. Whenever that model is used, your schema filter will apply. The other way is to add it to the options when you configure SwaggerGen. For this example I’ll be adding it to the model for this example, so annotate your model class like so:

And you’ll need the Annotations using statement:

And finally modify your controller method to take in the model class as a parameter:

Now if you run the code, navigate to Swagger, and open that controller method, you’ll see your example model set out to the right hand side, and clicking in the box will add that model to the value text box, allowing you to post data without worrying about anything.

Example model in Swagger
Example model in Swagger

Getting up and running with Swagger/Swashbuckle is as easy as that!
I’m still playing with this and learning more, as I’m sure there’s plenty of cool stuff I haven’t found yet, so will post an update if I find out anything useful.
And please feel free to let me know if you’ve come across anything I should know about!