18

On loading the plugin and trying to create 'XYZ' control, the application throws the following exception:

"The component 'XYZ' does not have a resource identified by the URI '/ThePluginAssembly;component/XYZ.xaml'" on the InitializeComponent() method in the UserControls constructor.

The key points are:

  1. The user control is located in the plugin assembly

  2. I am trying to create the usercontrol from inside the plugin assembly

  3. The plugins are located in the same directory as the main application

  4. The user controls only have problems when they are created through XAML. I have a couple of other usercontrols in the same assembly but I instantiate these using code. I only receive the error message when I attempt to create a UserControl in XAML.

On doing some google, i realized that this happens when two instances of my plugin are loaded in the application. When i removed my plugin from one of the folders ( I allow this plugin to be loaded from two locations) this exception stopped recurring.

My questions:

1) What is the reason behind WPF trying to resolve a URI to load my control?

2) Isn't there a way by which i could have two instances of my plugin loaded in the application and somehow get rid of this exception? or some way to create a unique URI for each instances (if this exception is caused by a conflicting URI).

Any comment or reference would be of help.

Thanks for your interest.

Edit: Same problem as posted by Phil : How to force WPF to use resource URIs that use assembly strong name? Argh!

Community
  • 1
  • 1
Manish Basantani
  • 16,931
  • 22
  • 71
  • 103
  • Why would you need, or event want two instances of an assembly? Once loaded the code is reusable. – Grant Thomas Feb 14 '11 at 15:06
  • 1
    Its not that i need, but i may have two difference versions of my plugins installed in the machine. And the main application will load one instance of each version, so two versions available. – Manish Basantani Mar 01 '11 at 13:23
  • See my post [here][1] for a generic way to set the assemby version. [1]: http://stackoverflow.com/a/28692813/1083111 – Traummaennlein Feb 24 '15 at 10:20

6 Answers6

9

The only way to do this would be to include the version information in your URI, so the XAML loader can distinguish the correct type. This MSDN article explains the Pack URI format, and the Version portion has this description:

;Version [optional]: the version of the referenced assembly that contains the resource file. This is used when two or more referenced assemblies with the same short name are loaded.

So you'd want to use one of the following:

/ThePluginAssembly;v1.0.0.0;component/XYZ.xaml
/ThePluginAssembly;v1.1.0.0;component/XYZ.xaml
CodeNaked
  • 40,753
  • 6
  • 122
  • 148
  • @Tom: Thanks for the post, it is related to my problem. But i could not figure out how should i instruct my application to append the version number before trying to resolve a URI !!!. For instance, if in MainForm i am using AdvancedFilter.xaml, then where would i instruct the MainForm to use /Plugin;v.x.x.x.x.;component/AdvancedFilter.xaml ?? Am i missing something? please help. – Manish Basantani Mar 04 '11 at 05:05
  • @Amby: Can you post the code that you use to load the XAML file? – CodeNaked Mar 04 '11 at 12:24
  • @Tom: I am not loading the xaml file by specifying the URI. I just create the WPF control on menuItem_click event. About loading the plugin, i load it using Assembly.Load(...), and this loads two available versions of my plugin. Also, please take a look at the related issue that i have mentioned in Edit. – Manish Basantani Mar 04 '11 at 13:37
  • @Amby: I see. In that case, your only option would be to implement a custom InitializeComponent method. You can simply copy the one that is generated for you and insert the version information in the Uri. Then you'd call your version (e.g. MyInitializeComponent) in the constructor of your class, not the one generated for you. – CodeNaked Mar 04 '11 at 14:35
  • @Tom: That really is a good solution, but is mechanical. Considering that i already have around 30 xaml controls!!. I was looking for some configuration that might do the trick, Since .g.cs is generated by the "MSBuild:Compile", i was expecting to hook some attribute/parameter to get the job done. – Manish Basantani Mar 05 '11 at 10:32
  • @Amby: Unfortunately, there isn't a setting like that at this time. – CodeNaked Mar 05 '11 at 16:55
2

try to use Assembly.LoadFrom() instead of Assembly.Load() or Assembly.LoadFile().

I had the same problem: I used to load assemblies with Assembly.LoadFile(). After searching for days, I found out that Assembly.LoadFile() and Assembly.Load() are deprecated. Both methods create problems in the runtime. So I used Assembly.LoadFrom() and it worked.

apaderno
  • 28,547
  • 16
  • 75
  • 90
  • 1
    `Assembly.LoadFile` and `Assembly.Load` are not deprecated, only certain overloads of them are deprecated, as is the case for `Assembly.LoadFrom`. The methods behave differently, so I suggest carefully reading the documentation and examining your own code before making this change, it shouldn't be modified unless you understand exactly what effect it's going to have. – Roger Sanders Feb 07 '17 at 04:28
1

The following directions are relevant for both the plugin's assembly and any non-System assembly referenced by the plugin (duplication could be at any level of references).

Since the plugin's assembly is located in the application's executable directory,
if you added your assembly to the GAC, remove it from there.

Check all references to the assembly from your solution and set "Version Specific" to false.

If the plugin assembly is from another solution and you use different versions of the assemble for debug/release or for x86/x64 then edit the .csproj files that reference the assembly and set a reference path like in this example.

Consider canceling reference to plugin assemblies and using reflection to load them instead - this will remove dependencies of solution upon plugins.
To do this, you will need to move any code that looks for specific elements in plugins to the plugin assemblies themselves and from original solution only access types exposed by plugin that support interfaces defined outside the plugin (by assemblies in original solution or in an assembly referenced by both original solution and plugin).
- While accessing assembly via reflection, make sure that you load the assembly from the application's executable directory.

Make sure the Pack URIs to resources are of the form: "pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml"

Community
  • 1
  • 1
Danny Varod
  • 17,324
  • 5
  • 69
  • 111
0

Copy all the files from bin folder into a separate folder from all the projects that are in your solution and remove the debug and release folder from the bin folder of each project. This has solved the designer problem for me.

Remember that when you will compile next time all the files will come back again. So you have to have some script in post build in order to copy to another folder and delete the files under bin folder.

Iftikhar
  • 79
  • 1
  • 5
0

So far, the best solution i have reached to, is modifying the name of my plugin dll in the project properties, and make it version specific.

So, if initially it was "prod.myplugin" now i have made it "prod.myplugin_300d3". After modifying the project properties when i rebuild my project then the compiler regenerates .g.cs files, and now it has a version in the URI (it appears as /prod.myplugin_300d3;component/XYZ.xaml ) and thus makes my URI uniquer across different versions.

I am still looking for a better, automated solution where i could be able to modify the MSBuild:Compile configuration.

Manish Basantani
  • 16,931
  • 22
  • 71
  • 103
0

I had same problem, my UserControls all referenced same Assembly as main app xaml. Removing resource link from UserControls resolve this problem.

NSKBpro
  • 373
  • 1
  • 14