Tuesday, August 15, 2023

Problem with MissingManifestResourceException for embedded resx files in subfolders

If you worked with .Net applications you most probably know what is embedded resources:

Such resources are embedded directly to output assembly. We may check them e.g. with decompiler:

 

Sometime we may need to change namespace of generated resources: e.g. in above example Foo.resx file is located in Resources sub folder so by default it will generate strongly typed class in namespace TestApp.Resources:

Note also line 42 when it created ResourceManager object - it also uses TestApp.Resources namespace. Now in properties of resx file we will explicitly specify Custom tool namespace = TestApp:

After that namespace of automatically generated class will be changed from TestApp.Resources to TestApp. However ResourceManager will be still created with the same old namespace TestApp.Resources:

We may modify .Designer.cs file manually and change namespace of ResourceManager to TestApp (note that if custom tool will run again it will override manual changes in cs file and they should be done again):

But if we will try to get string from generated class Foo.Bar we will get MissingManifestResourceException:

Unhandled exception. System.Resources.MissingManifestResourceException: Could not find the resource "TestApp.Foo.resources" among the resources "TestApp.Resources.Foo.resources" embedded in the assembly "TestApp", nor among the resources in any satellite assemblies for the specified culture. Perhaps the resources were embedded with an incorrect name.

The problem is that after our changes resx file is still embedded to the assembly as TestApp.Resources.Foo.resources:

In order to fix this error we need to edit csproj file and add LogicalName element under EmbeddedResource element for our resx file with correct name:

<EmbeddedResource Update="Resources\Foo.resx">
  <Generator>ResXFileCodeGenerator</Generator>
  <LastGenOutput>Foo.Designer.cs</LastGenOutput>
  <CustomToolNamespace>TestApp</CustomToolNamespace>
  <LogicalName>TestApp.Foo.resources</LogicalName> 
</EmbeddedResource>

After that resource will be embedded to the assembly with correct name TestApp.Foo.resources:

and exception will gone

Tuesday, August 8, 2023

Camlex and Camlex.Client 5.4.2 released

New version 5.4.2 of Camlex library has been released. Starting with this version it became possible to generate CAML queries with string operators BeginsWith and Contains for ContentTypeId field type e.g. the following C# code:

Camlex.Query().Where(x => ((DataTypes.ContentTypeId)x["ContentTypeId"]).StartsWith("0x123")).ToString(true);

will generate the following CAML query:

<Query>
  <Where>
    <BeginsWith>
      <FieldRef Name="ContentTypeId" />
      <Value Type="ContentTypeId">0x123</Value>
    </BeginsWith>
  </Where>
</Query>

This is useful since when you add some site content type to SharePoint list under the hood SharePoint creates inherited content type (which has ContentTypeId which starts with ContentTypeId of parent site content type with appended 00 symbols and guid without dashes) and exactly this inherited content type is then used for list items created in this list. In order to fetch all items created with original site content type we may use CAML query with BeginsWith operator and ContentTypeIdof parent site content type.

As usual new version is available via Nuget.