Home > Software engineering >  ASP.NET Core and View conflict resolution
ASP.NET Core and View conflict resolution

Time:11-12

I'm trying to build a plugin system for ASP.NET Core application. I have a folder inside the app called 'Plugins'.

In general, a plugin looks like a folder containing two files: Plugin.dll and Plugin.Views.dll The app scans this folder and loads these assemblies

foreach (var ext in extensionManager.Extensions)
{
    mvcBuilder.AddApplicationPart(ext.Assembly);
    if (ext.ViewsAssembly != null)
    {
        mvcBuilder.AddApplicationPart(ext.ViewsAssembly);
    }
}

If these plugins have ViewComponents with the same name I get an error. Model from Plugin1 may be passed into Plugin2's Razor View.

The model item passed into the ViewDataDictionary is of type 'Plugin1.Models.MyModel', 
but this ViewDataDictionary instance requires a model item of type 'Plugin2.Models.MyModel'

How can I resolve this conflict?

CodePudding user response:

The model item passed into the ViewDataDictionary is of type 'Plugin1.Models.MyModel', but this ViewDataDictionary instance requires a model item of type 'Plugin2.Models.MyModel'

You can try to use the full name Plugin2.Models.MyModel if this ViewDataDictionary instance requires a model item of type Plugin2.Models.MyModel.So that it will not pass Plugin1.Models.MyModel to this ViewDataDictionary.

CodePudding user response:

I solved the issue by adding this Target to my plugins' .csproj files:

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

I took this answer as a basis. I also delete the Include attribute from the RazorGenerate tag because it duplicates RazorCompiledAttribute in the resulting assembly.

On the host app's side, I extended view location formats with:

services.Configure<RazorViewEngineOptions>(opts =>
{
    var pluginName = ext.Assembly.GetName().Name;
    opts.ViewLocationFormats.Add($"/{pluginName}/Views/Shared/{{0}}.cshtml");
    opts.ViewLocationFormats.Add($"/{pluginName}/{{1}}/Views/{{0}}.cshtml");
});

In the plugin I must specify the fully qualified path to the view:

return View($"/{this.GetType().Assembly.GetName().Name}/Views/Path/To/MyView.cshtml", model);
  • Related