Miniblog.Core Virtual Application leads to System.NullReferenceException... at WebOptimizer.Taghelpers…
Miniblog.Core is pretty awesome. It’s small, optimized, has a ton of features, and is usually easy to setup. If I am running Miniblog.Core as just the root website, I can have it setup in minutes. However, upon trying to run Miniblog.Core in a /blog subdirectory off the main IIS website (i.e. a virtual application, not a virtual directory), it should otherwise be straight forward and pretty much is once you get over the couple hurdles I encountered.
Upon initial publishing, you need to comment out the duplicate handler that gets created within the Miniblog.Core web.config file:
<!-- <handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers> –>
This handler gets added automatically (even if you don’t have a web.config file in your project) and is only required for the root application/website and is erroring because of the duplicate name. (Luckily I found the workaround to this initial error while researching the issue for the following error.) However, once that 500 – Internal Server error is out of the way, you then run into yet another HTTP 500 Internal Server Error (in a slightly different format). Upon further investigation of the application event log (or logging in the app), you find:
Category: Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer
EventId: 2
RequestId: 800007c3-000e-bf00-b63f-84710c7967bb
RequestPath: /blog/
SpanId: |e21f856f-43a1440405eabe7c.
TraceId: e21f856f-43a1440405eabe7c
ParentId:Connection ID "13763000522984392642", Request ID "800007c3-000e-bf00-b63f-84710c7967bb": An unhandled exception was thrown by the application.
Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at WebOptimizer.Taghelpers.LinkTagHelper.Process(TagHelperContext context, TagHelperOutput output)
at Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.RunAsync(TagHelperExecutionContext executionContext)
at AspNetCore.Views_Shared__Layout.<>c__DisplayClass52_0.<<ExecuteAsync>b__0>d.MoveNext() in D:\Documents\Visual Studio 2019\Projects\Simple.Minicore.Blog\src\Views\Shared\_Layout.cshtml:line 17
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
at AspNetCore.Views_Shared__Layout.ExecuteAsync() in D:\Documents\Visual Studio 2019\Projects\Simple.Minicore.Blog\src\Views\Shared\_Layout.cshtml:line 4
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at WebMarkupMin.AspNetCore2.WebMarkupMinMiddleware.ProcessAsync(HttpContext context, Boolean useMinification, Boolean useCompression)
at WebMarkupMin.AspNetCore2.WebMarkupMinMiddlewareBase.Invoke(HttpContext context)
at WebEssentials.AspNetCore.OutputCaching.OutputCacheMiddleware.ServeFromMvcAndCacheAsync(HttpContext context)
at WebEssentials.AspNetCore.OutputCaching.OutputCacheMiddleware.InvokeAsync(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at WilderMinds.MetaWeblog.MetaWeblogMiddleware.Invoke(HttpContext context, MetaWeblogService service)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
at Microsoft.AspNetCore.Builder.Extensions.UsePathBaseMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()
NullreferenceExceptions are pretty easy to troubleshoot when it’s your own code. However, I can see that it’s WebOptimizer causing the error. While I messed around with this for hours trying many different IIS configurations and such to resolve whatever path issue the WebOptimizer package was having (and we mostly know it’s a pathing issue because it works at the root level), I wasn’t able to figure out what it needed to ultimately work like a root Miniblog.Core installation (i.e. problem free). After commenting out all the WebOptimizer code and getting it to work, yet formatted all wonky, I then simply tried leaving all WebOptimizer references in, except the addTagHelper in the _ViewImports.cshtml file:
@*@addTagHelper *, WebOptimizer.Core*@
At this point, I don’t know WebOptimizer enough to know specifically what issues I’ll run into in the future by removing this, but I know the realm and so far everything looks normal.
One last thought, you also can’t have your application pools the same for your root website and virtual application (i.e. Miniblog.Core). Therefore, you’ll need to create a new application pool and assign Miniblog.Core to it. However, if you run into this error, it’s blatantly obvious as they tell you exactly what the issue is as opposed to some of these more cryptic errors.
UPDATE: Turns out I had to edit (essentially remove) all the "/blog" routes in the BlogController too (only the "/blog" portion of the route, leave the rest of the route), and maybe a few others. Otherwise, I'd have to route to /blog/blog/etc for every route. Just search "/blog", but don't do a blanket replace. There might be a more clever way to work with the virtual paths, but can't think of anything now and I'll have to investigate later.
Comments
Comments are closed