Laying A Foundation
I've recently had some conversations with other developers about setting up and configuring projects.
I work ๐ทโโ๏ธ for a web development and marketing agency, WiredViews. Working for an agency involves a constant stream of greenfield projects, which means I've had lots of experience "starting" things.
Below I'd like to cover some recommendations for setting up a Kentico 12 MVC project and what benefits these bring.
This is going to be a 3-part post. In this post we're going to look at Documentation.
The previous posts were about Developer Experience and Documentation.
Let's begin!
Configuration
Configuration represents all the switches and buttons that toggle how our projects work, when we are developing, deploying, and running our apps.
Using HTTPS Locally
Trying to make our local development environments as much like the staging and production servers as possible is something that we developers always strive for.
Docker is great at solving this problem, but classic Full Framework .NET applications aren't the best use-case ๐ (unlike .NET Core, which works great with Docker).
Fortunately, there are configuration changes we can make to our Kentico 12 MVC code base to at least enable HTTPS for local development ๐๐พ.
First, this can either be accomplished by running the site out of IIS locally or using IIS Express.
I've done both, but my recommendation is to use IIS Express, due to the way it's integrated with Visual Studio.
Now, if we open the .csproj
files for both the Content Delivery (MVC) and Content Management (CMS) applications, we can make sure we have all the settings correctly defined.
Inside the first <Project><PropertyGroup>
node, we'll want to set 2 properties:
<Project ...>
<Import ...>
<PropertyGroup>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort>44325</IISExpressSSLPort>
We can set the <IISExpressSSLPort>
to whatever we want, as long as its in the 44300 to 44399 range.
We will want different values here for the 2 different web application .csproj
files (example: 44325 and 44326).
Next, we need to define some Visual Studio configuration in the <Project><ProjectExtensions>
node:
<Project ...>
<!-- Lots of other stuff -->
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>51872</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>https://localhost:44325/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
Here we can set the <DevelopmentServerPort>
(HTTP) value to whatever we want, typically in the 50000-59999 range, and the <IISUrl>
to be https://localhost:
plus the port we picked for <IISExpressSSLPort>
.
Do this for both the Content Management and Content Delivery applications and open up the solution in Visual Studio.
When we run the apps we should be able to load them over https://
using the ports we defined ๐๐พ.
Running
https://
locally can be great for catching Mixed Content Warnings early in the development process ๐ or testing HSTS.
Using <PackageReference>
for NuGet
The Kentico Installation Manager can be used to create new applications or update existing ones.
When creating a new Kentico 12 MVC application, we are given 2 ASP.NET projects - one for content management (the classic CMS application) and one for content delivery (the MVC application).
Both are created using the outdated (but still functional) packages.config style of NuGet package management ๐.
.NET Core uses <PackageReference>
, which I've written about in my post Kentico 12 Class Libraries with Modern .NET Core Features.
Kentico 12 Class Libraries with Modernย .NET Core Features
Sean G. Wright ใป Jun 1 '19
Read about the benefits of
<PackageReference>
in Microsoft's documentation ๐ง!
Unfortunately, Visual Studio 2019 no longer supports migrating packages.config
to <PackageReference>
for ASP.NET projects ๐๐พโโ๏ธ.
Fortunatley, we can trick Visual Studio into thinking our project is just another C# class library ๐ฎ!
If we open up the .csproj
for one of our projects, we can see an MSBuild property <ProjectTypeGuids>
:
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
Using a reference for these identifiers we can see that 349c5851-65df-11da-9384-00065b846f21
represents an ASP.NET project and fae04ec0-301f-11d3-bf4b-00c04f79efbc
represents a C# project.
Let's temporarily replace with <ProjectTypeGuids>
:
<ProjectTypeGuids>{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
Now our project is no longer seen as an ASP.NET project by Visual Studio and we'll see the "Migrate" option when right clicking the packages.config
file.
We can perform the migration and be one step closer to an ASP.NET Core project - no more needing to manage .NET Framework version for packages or have all the transitive dependencies enumerated our packages list ๐ช๐ฝ!
Once complete we need to make sure to revert the <ProjectTypeGuids>
to the original value so that Visual Studio lights up with the correct ASP.NET features we've come to expect for our project.
Web.config transforms for production
When working on our project locally we might have all our configuration defined in the web.config
- connection strings, app settings, URL Rewrite rules, debug flags...
But what happens when we deploy our application to another environment where some of these values should change ๐ค?
Our first approach might be changing the values manually each time we deploy, but this is error prone and requires an additional deployment step (doubly error prone ๐ฑ!)
A better option is to use the web.config
transforms functionality that is built into MSBuild and Visual Studio.
Assume we have a web.config
with the following configuration:
<system.web>
<compilation debug="true" targetFramework="4.7.2"/>
<!-- ... -->
We want the debug="true"
locally because we want to hit breakpoints in Visual Studio correctly when running our site.
Then, when we deploy the app to any environment where we are running it outside of Visual Studio, we want to remove that attribute because of the significant performance impact it can have.
In a new ASP.NET project we should be able to right-click the web.config
file, in the Solution Explorer in Visual Studio, and see the "Add Config Transform" option.
Click this will add a new file that is a set of instructions to "transform" the web.config
for a specific build configuration (eg: Debug vs Release).
After adding the transform we can see (2) new files - web.Debug.config
and web.Release.config
:
Opening up the web.Release.config
we can see that Visual Studio has already done us a favor by adding the transform instruction to remove the debug
attribute when publishing the app using the Release configuration ๐.
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
Now, whether we are publishing to the local filesystem, IIS on a virtual machine, or an Azure App Service, we can be sure our deployed web.config
will have the right values for that environment ๐๐ผ.
If you want to learn more about how to "publish" an ASP.NET application from Visual Studio, check out the official Microsoft documentation.
AppSettings.Local.config
Another way we can take advantage of web.config
transforms is with our app settings (and similarly, connection strings).
We don't want to commit sensitive settings into source control, and other team members might want their own local settings ๐.
We can create local configuration files that are set as the default paths in our web.config
and then transform these values to the normal, committed files when publishing.
Here's an example of what the base web.config
looks like:
Notice, there's no sensitive values or ones other developers might want to configure here.
<appSettings file="App_Config\AppSettings.Local.config">
<add key="webpages:Version" value="3.0.0.0"/>
<add key="webpages:Enabled" value="false"/>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
<add key="aspnet:MaxJsonLength" value="20971520"/>
</appSettings>
<connectionStrings configSource="App_Config\ConnectionStrings.Local.config"/>
The App_Config\AppSettings.Local.config
and App_Config\ConnectionStrings.Local.config
are both ignored by source control and also not included in the .csproj
.
They include the sensitive and customizable values we use locally when developing ๐:
<appSettings>
<add key="CMSHashStringSalt" value="..."/>
<add key="CMSAzureAccountName" value="..."/>
<add key="logging:serilog:log-level" value="Debug" />
The web.Release.config
then contains a transform instruction to point the source of our settings and connection strings to other files:
<appSettings
file="App_Config\AppSettings.config"
xdt:Transform="SetAttributes(file)">
</appSettings>
<connectionStrings
configSource="App_Config\ConnectionStrings.config"
xdt:Transform="SetAttributes(configSource)" />
These two files (App_Config\AppSettings.config
and App_Config\ConnectionStrings.config
) are both included in the .csproj
and source control, but they don't include any sensitive values ๐คจ.
Instead they are either empty (settings could be defined in an Azure App Service directly) or contain tokens that can be replaced by a continuous delivery tool or extension).
URL Rewrite Redirect to CMS Admin
Another cool use of web.config
transforms is changing the value of a URL Rewrite rule:
This rule would be added to our Content Delivery application (MVC) web.config
.
It says any request for /admin
should be redirected to the Content Management application (CMS) which can be found at https://localhost:44326/admin
locally ๐ค.
<system.webServer>
<rewrite>
<rules>
<rule name="Admin-Redirect">
<match url="^admin"/>
<action type="Redirect" url="https://localhost:44326/admin"/>
</rule>
</rules>
</rewrite>
<!-- ... -->
However, in production that domain is different. This means in our web.Release.config
we have a transform for this URL rewrite rule.
<system.webServer>
<rewrite>
<rules>
<rule xdt:Transform="Replace" xdt:Locator="Match(name)"
name="Admin-Redirect">
<match url="^admin"/>
<action type="Redirect"
url="https://admin.your-domain.com/admin"/>
</rule>
</rules>
</rewrite>
<!-- ... -->
I like this solution a lot more ๐ than the one recommended in the Kentico documentation that performs the redirect at the ASP.NET level instead of the IIS level.
Less code, more performant ๐ช๐ฟ!
Conclusion
In this post we looked at the many ways we can improve our Kentico 12 MVC projects by adjusting how they are configured. .csproj
settings, NuGet package management, and web.config
transforms.
Much of this configuration can be found 'behind the scenes' in an ASP.NET project, which is both good and bad. We don't need to worry about it when getting started (good ๐!) but we also might not know it's there when we need to customize it (not so good ๐!).
None of these things are Kentico specific, but if we are new to Kentico or .NET, these suggestions might also be new and helpful.
Hopefully this post pulls back the curtain some and encourages you to explore how you can configure your Kentico 12 MVC project to work better for you and your team.
...
As always, thanks for reading ๐!
We've put together a list over on Kentico's GitHub account of developer resources. Go check it out!
If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:
Or my Kentico blog series:
Top comments (0)