Pages

Thursday 11 June 2020

Remote debug Umbraco on Azure Web App

The title is a bit misleading, because you can debug ANY Azure Web App, not just when running Umbraco, but I had to keep it a bit Umbraco related.

When everything works

If everything was always working, I wouldn't be writing about it today. There's plenty of guides to show you how to do remote debugging, when everything is fine.

In my experience - more often than not - there's always some crucial little step, preventing you from quickly attaching a debugger and finding the exact cause of that elusive error that you just can't reproduce on your local environment.
Remote debugging has saved me HOURS of trying to get to that one error that only one of your users is experiencing in production.

Under normal circumstances, you would
  • publish your Web App from Visual Studio in debug mode. 
  • go to your Cloud Explorer, scroll down to your web app
  • click Attach debugger (this will activate remote debugging if not already active)
 

What can possible go wrong?

Well, you could:
  • not be able to publish for some reason
  • have forgotten to put it in Debug mode
  • not see your Web App in Cloud Explorer, even though your seeing everything else and you DO have access in the Azure Portal and IT already verified that everything is working
    (clearly, I'm speaking hypothetically, because this never happens)

Do it all yourself

Enable remote debugger

First, you'll need to enable remote debugging on your Web App.
  • Go to your Web App in the Azure Portal.
  • Go to Configuration > General Settings
  • Enable Remote Debugging and choose your version of Visual Studio

Download the PublishProfile

The PublishProfile contains all endpoints and credentials you'll need for accessing this Web App.
You can download it from the Overview blade.


The file looks like this.
Obviously, I've fudged it a bit, so you wouldn't get any ideas of trying to mess with my app.
<publishData>
	<publishProfile profileName="[yourApp] - Web Deploy" publishMethod="MSDeploy" publishUrl="[yourApp].scm.azurewebsites.net:443" msdeploySite="[yourApp]" userName="$[yourApp]" userPWD="[yourAppPassword]" destinationAppUrl="http://[yourApp].azurewebsites.net" SQLServerDBConnectionString="" mySQLDBConnectionString="" hostingProviderForumLink="" controlPanelLink="http://windows.azure.com" webSystem="WebSites">
		<databases />
	</publishProfile>
	<publishProfile profileName="[yourApp] - FTP" publishMethod="FTP" publishUrl="ftp://[yourAppFTP].ftp.azurewebsites.windows.net/site/wwwroot" ftpPassiveMode="True" userName="[yourApp]\$[yourApp]" userPWD="[yourAppPassword]" destinationAppUrl="http://[yourApp].azurewebsites.net" SQLServerDBConnectionString="" mySQLDBConnectionString="" hostingProviderForumLink="" controlPanelLink="http://windows.azure.com" webSystem="WebSites">
		<databases />
	</publishProfile>
	<publishProfile profileName="[yourApp] - ReadOnly - FTP" publishMethod="FTP" publishUrl="ftp://[yourAppFTP]dr.ftp.azurewebsites.windows.net/site/wwwroot" ftpPassiveMode="True" userName="[yourApp]\$[yourApp]" userPWD="[yourAppPassword]" destinationAppUrl="http://[yourApp].azurewebsites.net" SQLServerDBConnectionString="" mySQLDBConnectionString="" hostingProviderForumLink="" controlPanelLink="http://windows.azure.com" webSystem="WebSites">
		<databases />
	</publishProfile>
</publishData>
The interesting bits are 
  • url - this should be "[yourApp].azurewebsites.net" (make sure there's no ".scm." part)
  • userName - make sure to take the fully qualified one : "[yourApp]\$[yourApp]"
  • userPWD

Attach your debugger

  • In Visual Studio, go to Debug > Attach to process (CTRL-ALT-P)
  • In the Connection target, paste your Url plus port 4022 (for VS2017, port 4024 for VS2019)
  • In the popup-window, paste username and password 
If your credentials are correct and there is no company firewall blocking your outgoing request, you should be able to see all running processes on the remote machine.
We want to attach to the w3wp.exe. If running a .Net Core application, this will be dotnet.exe.


And that's it, you are now remote debugging Umbraco (or whatever you're working on) and can put breakpoints where you think the problems occur.

Troubleshooting

Now, there are numerous things in the preceding steps that can go wrong and possibly many more that I haven't even encountered yet myself.

Cannot attach debugger

You get an error after entering the url of the Web App, or the popup asking for credentials does not appear.

It's most likely a connectivity issue.
  • Check your corporate firewall.
  • Check if it works from home (while not on any VPN), or tether via your mobile.
  • Check your Web App for IP filtering.

Cannot activate breakpoints

The version of your code doesn't match the version running on your Web App.
  • Try republishing the latest version.
  • Try finding the source branch that matches this release.
If the problem you're investigating is in a specific class library, try building a new version of that project only and push that .dll and it's accompanying .pdb via Kudu or FTP (you have the ftp-credentials in the PublishProfile you downloaded earlier).

Make a backup of the existing .dll, so you can quickly revert.

Thursday 4 June 2020

DocTypeGridEditor - Remove default DocType option

As I mentioned in my previous post, I'd be checking to get rid of the default "Doc Type" option in the popup below.
It allows your editors to choose any DocType (marked as "Element") and we can think of reasons why you wouldn't want this option to be available to them.


Even if you didn't mention it in your grid.editors.config.js, the "Doc Type" option is always there.

Turns out it's defined in the manifest-file (App_plugins\DocTypeGridEditor\package.manifest). If you make that gridEditors-property into an empty array, the option will no longer be there.

{
  "gridEditors": [],
  "javascript": [
    "~/App_Plugins/DocTypeGridEditor/Js/doctypegrideditor.resources.js",
    "~/App_Plugins/DocTypeGridEditor/Js/doctypegrideditor.services.js",
    "~/App_Plugins/DocTypeGridEditor/Js/doctypegrideditor.controllers.js",
    "~/App_Plugins/DocTypeGridEditor/Js/doctypegrideditor.directives.js"
  ],
  "css": [
    "~/App_Plugins/DocTypeGridEditor/Css/doctypegrideditor.css"
  ]
}

I hope anyone can benefit from this. See you around!

DocTypeGridEditor - partial view was not found

We've been working with DocTypeGridEditor for years, but just once in a while, there's an issue that takes more than 5 minutes to isolate.

I'm going to assume you know what I'm talking about, for an intro to DTGE will take too much time and can be found elsewhere.

Below is the popup that the users get when adding a control to the grid.


Embed, Image, Macro and Rich text are there by default. Headline and Quote is something we replaced in our base project. Widget is something specific for the project I'm working on.

The problem is the "Doc Type" option. It's not configured in the grid.editors.config.js where you control which controls the editors can pick. It must be added behind the scenes by the DTGE implementation somehow.

For some reason, however, if one of our editors picked "Doc Type" instead of one of the others, it yields the following error:
System.InvalidOperationException: The partial view 'richTextBlock' was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/ContentPage/richTextBlock.aspx
~/Views/ContentPage/richTextBlock.ascx
~/Views/Shared/richTextBlock.aspx
~/Views/Shared/richTextBlock.ascx
~/Views/ContentPage/richTextBlock.cshtml
~/Views/ContentPage/richTextBlock.vbhtml
~/Views/Shared/richTextBlock.cshtml
~/Views/Shared/richTextBlock.vbhtml
~/Views/Partials/richTextBlock.cshtml
~/Views/MacroPartials/richTextBlock.cshtml
~/Views/richTextBlock.cshtml
   at System.Web.Mvc.HtmlHelper.FindPartialView(ViewContext viewContext, String partialViewName, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at Our.Umbraco.DocTypeGridEditor.Web.Extensions.HtmlHelperExtensions.RenderDocTypeGridEditorItem(HtmlHelper helper, IPublishedElement content, String editorAlias, String viewPath, String previewViewPath, Boolean isPreview)
   at ASP._Page_app_plugins_doctypegrideditor_render_doctypegrideditor_cshtml.Execute() in C:\Projects\DPW\Website\ProjectV8.Site\app_plugins\doctypegrideditor\render\doctypegrideditor.cshtml:line 28
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in d:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at ASP._Page_Views_Partials_grid_editors_base_cshtml.Execute() in C:\Projects\DPW\Website\ProjectV8.Site\Views\Partials\grid\editors\base.cshtml:line 20

Using the richTextBlock directly works fine, so after some head-scratching I discovered that we usually declare our components as follows:
  {
    "name": "Headline",
    "alias": "headline",
    "view": "/App_Plugins/DocTypeGridEditor/Views/doctypegrideditor.html",
    "icon": "icon-coin",
    "render": "/App_Plugins/DocTypeGridEditor/Render/DocTypeGridEditor.cshtml",
    "config": {
      "allowedDocTypes": [
        "headlineBlock"
      ],
      "nameTemplate": "",
      "enablePreview": true,
      "viewPath": "/Views/Partials/Grid/Editors/",
      "previewViewPath": "/Views/Partials/Grid/Editors/",
      "previewCssFilePath": "",
      "previewJsFilePath": ""
    }
  }
Some debugging showed me that the "Doc Type" definition, which is added automatically, even if you want it or not, is this:
  {
    "name": "Doc Type",
    "alias": "docType",
    "view": "/App_Plugins/DocTypeGridEditor/Views/doctypegrideditor.html",
    "render": "/App_Plugins/DocTypeGridEditor/Render/DocTypeGridEditor.cshtml",
    "icon": "icon-item-arrangement",
    "config": {
      "allowedDocTypes": [],
      "nameTemplate": "",
      "enablePreview": false,
      "viewPath": "/Views/Partials/Grid/Editors/DocTypeGridEditor/",
      "previewViewPath": "/Views/Partials/Grid/Editors/DocTypeGridEditor/Previews/",
      "previewCssFilePath": "",
      "previewJsFilePath": ""
    }
  }
The difference is the viewPath-property, ending in /DocTypeGridEditor/, which we do not have. Historical reasons, I guess.

The only way to override this default behavious is by manually adding the DocType configuration to the grid.editors.config.js, with the correct path of course.

Now, if I find a way to eliminate the Doc Type option altogether, I'll let you know.