RazorFormat NULLREF

After getting NULLREF after upgrading to the SS 5.6, it took me some time to realise the changes on the RazorFormat API. Can you please change the code below?

public ViewEngineResult GetPageFromPathInfo(string pathInfo)
        {
            if (pathInfo.EndsWith("/"))
                pathInfo += "default.cshtml";

            var viewPath = "~/wwwroot".CombineWith(pathInfo);
            if (!viewPath.EndsWith(".cshtml"))
                viewPath += ".cshtml";

            var viewEngineResult = ViewEngine.GetView("", viewPath, 
                isMainPage: viewPath == "~/wwwroot/default.cshtml");

            if (!viewEngineResult.Success)
            {
                viewPath = PagesPath.CombineWith(pathInfo);
                if (!viewPath.EndsWith(".cshtml"))
                    viewPath += ".cshtml";

                viewEngineResult = ViewEngine.GetView("", viewPath,
                    isMainPage: viewPath == $"{PagesPath}/default.cshtml");
            }

            return viewEngineResult.Success 
                ? viewEngineResult 
                : null;
        }

This is in RazorFormat.cs. It will return NULL when a view is not found, but the calling code does not explain which view and also does not mention which paths are searched.

In the end the following method gives the actual NULLREF:

    private ViewEngineResult FindView(IEnumerable<string> viewNames, out Dictionary<string, object> routingArgs)
    {
        routingArgs = null;
        const string execPath = "";
        foreach (var viewName in viewNames)
        {
            if (viewName.StartsWith("/"))
            {
                var viewEngineResult = GetPageFromPathInfo(viewName);                
                if (viewEngineResult.Success) // <-- NULLREF
                    return viewEngineResult;
        
                viewEngineResult = GetRoutingPage(viewName, out routingArgs);                
                if (viewEngineResult.Success) // <-- NULLREF
                    return viewEngineResult;
            }
            else
            {
                foreach (var location in ViewLocations)
                {
                    var viewPath = location.CombineWith(viewName) + ".cshtml";
                    var viewEngineResult = ViewEngine.GetView(execPath, viewPath, isMainPage: false);
                    if (viewEngineResult.Success) // <-- NULLREF
                        return viewEngineResult;
                }
            }
        }

        return null;
    }

It would be awesome to know all paths searched and the name of the view that gives the error.

Are you sure there’s a null ref after calling MVC’s ViewEngine.GetView()? That shouldn’t return null.

The NRE’s should now be guarded against in this commit.

This change is available from v5.6.1 that’s now available on MyGet.

Yes, it was an NRE
It’s easily tested by having a service method that sets the view to something nonexistent.

.I understand the commit, but that would not help to find the view that is not found. Any chance of getting this extended to which view it is that is not found (and possibly the paths checked?)

I will amend this post with a PoC for this. Feel free to use it when done (takes a day or two)

For now, thanks for the quick fix.

I mean specifically for MVC’s RazorViewEngine.GetView() it’s implementation suggests it never returns null.

image

This piece results in a NULL returned.

Then, this is NULL:

image

which in turn triggers the NRE:

image

I would opt for NOT returning a NULL from the first function. That was my suggestion. It is then also possible to notify the developer of the view that is not found. In my case it was fixed by adding the right base path to the RazorFormat plugin:

image

Yes I know my API’s return null and my commit resolves the NRE when there’s no Views, I’ve only asked about MVC’s APIs:

The ViewEngineResult is never created by ServiceStack and we always return null to indicate when an entry isn’t found.