4
votes

I'm trying to use the new Razor SDK to include my views within my class libraries where each class library is an MVC Area. If I include the views with an Areas directory in my class library e.g.

/MyLibrary/Areas/MyLibrary/Views/Home/Index.cshtml

Then it loads fine. However I don't like that I have to place them inside an Areas directory ideally the path would be:

/MyLibrary/Views/Home/Index.cshtml

I'm guessing I would have to use a view location expander to achieve this. However I don't know how to achieve this for a view which is contained within a class library and not within the application. So far I have come up with:

public class AreaViewLocationExpander : IViewLocationExpander {
    public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) {
        return viewLocations.Concat(new[] {
            "../{2}/Views/{1}/{0}" + RazorViewEngine.ViewExtension
        });
    }

    public virtual void PopulateValues(ViewLocationExpanderContext context) { }
}

This throws the error:

InvalidOperationException: The view 'Index' was not found. The following locations were searched:

/Areas/MyLibrary/Views/Home/Index.cshtml

/Areas/MyLibrary/Views/Shared/Index.cshtml

/Views/Shared/Index.cshtml

/Pages/Shared/Index.cshtml

/../MyLibrary/Views/Home/Index.cshtml

But I'd imagine even if it did work locally, it wouldn't in production or when the library is packaged up in a NuGet package.

I'd appreciate it if someone could show me how this can be achieved. Thanks

1
Curious. Why did you go up a level to get to your library?Nkosi
I assumed the path would start at the application root. The class library is in the same directory as the application and therefore i’d have to go up a directory to get to it. I thought this would work during development atleast.nfplee
when compiled the referenced libraries would be in the bin.Nkosi
Check this out and see if it can be modified for views davepaquette.com/archive/2016/07/16/…Nkosi
Yeah I’m aware of that but I need to load the views within the dll using a different path.nfplee

1 Answers

2
votes

Step 1

From @pranavkm on GitHub:

The Razor Sdk uses well-known MSBuild metadata to calculate project relative paths. You may set the Link metadata for a file and Razor would use that. For instance, adding this to your project file would update all cshtml files to have a view engine path with the project name as a prefix:

<Target Name="UpdateTargetPath" BeforeTargets="AssignRazorGenerateTargetPaths">
  <ItemGroup>
    <RazorGenerate Include="@(RazorGenerate)" Link="$(TargetName)\%(RazorGenerate.RelativeDir)%(RazorGenerate.FileName)%(RazorGenerate.Extension)" />
  </ItemGroup>
</Target>

This does not work with runtime compilation - i.e. if you were to apply this to Application.csproj, it'll work for build time compiled views, but runtime compiled views would continue to use /Views/Home/Index.cshtml

Step 2

You would then need to add the following IViewLocationExpander:

public class AreaViewLocationExpander : IViewLocationExpander {
    public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) {
        return viewLocations.Concat(new[] {
            "/{2}/Views/{1}/{0}" + RazorViewEngine.ViewExtension
        });
    }

    public virtual void PopulateValues(ViewLocationExpanderContext context) { }
}