Cannot Find Type Converter

Posts   
 
    
JSStudz
User
Posts: 42
Joined: 08-Jul-2019
# Posted on: 13-Nov-2019 15:13:07   

We recently changed the folder where our additional type converters were being pointed at. Upon doing so we get an error saying that it cannot find our custom type converter. I have confirmed that the .dll is in the new folder.

We are running EF Core 3.0 and NetStandard 2.1.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 13-Nov-2019 15:52:57   

The 'additional typeconverter folder' in the project is also the new folder? This is a catch 22, as you can only look at it when the project is loaded, and you can't do that as the typeconverter can't be found, so please load the llblgenproj file in notepad++ and check the <Property Name="AdditionalTypeConverterFolder" Value="" /> line (it's almost at the top, line 9 or so).

the typeconverter dll hasn't changed, as in, it's still compiled with .net framework ?

Frans Bouma | Lead developer LLBLGen Pro
JSStudz
User
Posts: 42
Joined: 08-Jul-2019
# Posted on: 13-Nov-2019 16:28:48   

Otis wrote:

The 'additional typeconverter folder' in the project is also the new folder? This is a catch 22, as you can only look at it when the project is loaded, and you can't do that as the typeconverter can't be found, so please load the llblgenproj file in notepad++ and check the <Property Name="AdditionalTypeConverterFolder" Value="" /> line (it's almost at the top, line 9 or so).

the typeconverter dll hasn't changed, as in, it's still compiled with .net framework ?

Yeah, everything compiles. We changed the folder both in settings and in an editor. Still run into the same issue.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 13-Nov-2019 17:43:52   

I can't reproduce it.

Which Designer version are you using?

JSStudz
User
Posts: 42
Joined: 08-Jul-2019
# Posted on: 13-Nov-2019 18:02:44   

Walaa wrote:

I can't reproduce it.

Which Designer version are you using?

5.6.1

this is an issue for all team members that we are experiencing

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 13-Nov-2019 18:15:42   

Please, paste the full line here, I want to see the value written in the file. <Property Name="AdditionalTypeConverterFolder" Value="" />

Also for the sake of trial, if you copy back the TypeConverter dll into the default folder, can you see it along with the correct types, if you open the designer (without opening a project), and go to Tools / View Loaded External Types ?

JSStudz
User
Posts: 42
Joined: 08-Jul-2019
# Posted on: 13-Nov-2019 18:22:09   

Walaa wrote:

Please, paste the full line here, I want to see the value written in the file. <Property Name="AdditionalTypeConverterFolder" Value="" />

Also for the sake of trial, if you copy back the TypeConverter dll into the default folder, can you see it along with the correct types, if you open the designer (without opening a project), and go to Tools / View Loaded External Types ?

<Property Name="AdditionalTypeConverterFolder" Value=".\bin\Debug\netstandard2.1" />

what do you mean default folder? the original folder? If so, no.

Edit:


Could not load file or assembly or one of its dependencies. The system cannot find the file specified.. Type converters in this assembly will be unavailable.

The .dll is there though.

Edit 2:

Put the .dll in the core typeconverter folder for LLBLGen and it still doesn't work.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 14-Nov-2019 10:05:21   

The folder suggests the typeconverter dll is compiled against .netstandard 2.1. However the designer is a .net framework app, and no .net framework version implements .net standard 2.1, therefor the dll can't be loaded. (assuming that's the case with your dll, you didn't specify this, nor did you give much other details).

For EF Core you have to derive from ValueConverter, which is indeed a .netstandard2.1 class as EF Core 3 is .netstandard 2.1. The designer doesn't work with 'ValueConverter' as it's a class from EF Core and it uses a generic type from System.ComponentModel, TypeConverter to define type converters. We do this to not being tied to a given EF Core version. The type converters supported out of the box for EF Core are based on system type converters which are merely placeholders to let the designer work with typeconverters and generate native types at generation time. Below I describe to do effectively that.

To solve this, you have to create a small assembly for the designer for your typeconverter(s), in which you define simple typeconverters which implement CanConvertFrom, CanConvertTo and the CreateInstance methods. Below is an example, for a simple converter between short and string, to map a string field on a short database field. This converter doesn't do any converting, it's just to tell the designer the converter is there and will be used at runtime.

This assembly should be compiled against .net framework, the version you've installed to run the designer, e.g. 4.7.2, and preferably should use the namespaces as with your actual typeconverter that's used at runtime.


using System;
using System.ComponentModel;

namespace TestTCs
{
    [Description("TestTC")]
    public class MySystemTC: TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(short);
        }
        

        /// <inheritdoc />
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string);
        }


        /// <summary>
        /// Creates an instance of the Type that this <see cref="T:System.ComponentModel.TypeConverter"/> is associated with (short)
        /// </summary>
        /// <param name="context">ignored.</param>
        /// <param name="propertyValues">ignored.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> of type short. It always returns 0 for this converter.
        /// </returns>
        public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
        {
            return "0";
        }
    }
}

When generating code into a new folder where the csproj file isn't yet present, the csproj file will have the path to this typeconverter dll. you have to change that once, this file isn't overwritten the next time.

Frans Bouma | Lead developer LLBLGen Pro
JSStudz
User
Posts: 42
Joined: 08-Jul-2019
# Posted on: 14-Nov-2019 13:04:39   

Otis wrote:

The folder suggests the typeconverter dll is compiled against .netstandard 2.1. However the designer is a .net framework app, and no .net framework version implements .net standard 2.1, therefor the dll can't be loaded. (assuming that's the case with your dll, you didn't specify this, nor did you give much other details).

For EF Core you have to derive from ValueConverter, which is indeed a .netstandard2.1 class as EF Core 3 is .netstandard 2.1. The designer doesn't work with 'ValueConverter' as it's a class from EF Core and it uses a generic type from System.ComponentModel, TypeConverter to define type converters. We do this to not being tied to a given EF Core version. The type converters supported out of the box for EF Core are based on system type converters which are merely placeholders to let the designer work with typeconverters and generate native types at generation time. Below I describe to do effectively that.

To solve this, you have to create a small assembly for the designer for your typeconverter(s), in which you define simple typeconverters which implement CanConvertFrom, CanConvertTo and the CreateInstance methods. Below is an example, for a simple converter between short and string, to map a string field on a short database field. This converter doesn't do any converting, it's just to tell the designer the converter is there and will be used at runtime.

This assembly should be compiled against .net framework, the version you've installed to run the designer, e.g. 4.7.2, and preferably should use the namespaces as with your actual typeconverter that's used at runtime.


using System;
using System.ComponentModel;

namespace TestTCs
{
    [Description("TestTC")]
    public class MySystemTC: TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(short);
        }
        

        /// <inheritdoc />
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string);
        }


        /// <summary>
        /// Creates an instance of the Type that this <see cref="T:System.ComponentModel.TypeConverter"/> is associated with (short)
        /// </summary>
        /// <param name="context">ignored.</param>
        /// <param name="propertyValues">ignored.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> of type short. It always returns 0 for this converter.
        /// </returns>
        public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
        {
            return "0";
        }
    }
}

When generating code into a new folder where the csproj file isn't yet present, the csproj file will have the path to this typeconverter dll. you have to change that once, this file isn't overwritten the next time.

Our Type Converter does derive from TypeConverter. I believe we had this discussion before about EF Core and TypeConverters.

Edit: Our TypeConverter had previously worked, now we are running into this issue when we are trying to make changes to our models and schema.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 14-Nov-2019 16:40:57   

Your reply didn't specify whether you have tried what Otis suggested or not.

Please try to follow our suggestions and reply accordingly so we are clear what's going on at your side.

Please confirm that the current dll is compiled against the same .NET Framework version as that of the Designer used?

After doing so, please report back whether the types are loaded or not, in the designer, if you put the dll in the original folder, and open the Designer without loading any project. I've specified where to look at, to check the loaded types when the designer starts (so you need to close it first if it's already open and re-open it again).

JSStudz
User
Posts: 42
Joined: 08-Jul-2019
# Posted on: 14-Nov-2019 17:04:42   

Walaa wrote:

Your reply didn't specify whether you have tried what Otis suggested or not.

Please try to follow our suggestions and reply accordingly so we are clear what's going on at your side.

Please confirm that the current dll is compiled against the same .NET Framework version as that of the Designer used?

After doing so, please report back whether the types are loaded or not, in the designer, if you put the dll in the original folder, and open the Designer without loading any project. I've specified where to look at, to check the loaded types when the designer starts (so you need to close it first if it's already open and re-open it again).

I apologize, that was all sort of jumbled together, or my coffee didn't kick in yet. I see what the issue is then. Really not sure why the .Net standard 2.1 didn't pop out first for you guys. wink

shannonm
User
Posts: 9
Joined: 08-Aug-2019
# Posted on: 14-Nov-2019 22:42:04   

Hey guys, working with JStudz on this. I'm new to LLBL but a little more familiar with the MS NET "Standard" mess. Yes, we are using EF Core 3.0. Given:

<Property Name="AdditionalTypeConverterFolder" Value=".\bin\debug\netstandard2.0\" />

<FieldMapping FieldName="RowVersion" TargetFieldName="RowVersion" TypeConverterToUse="Company.Data.Context.ByteIntConverter" />

<TypeConversionDefinitions>
<TypeConversionDefinition TypeConverter="Company.Core.TypeConverters.ByteIntConverterCapabilities" DbDotNetType="System.Byte[]" FilterDbType="21" />
</TypeConversionDefinitions>

where:

ByteIntConverterCapabilities : TypeConverter
ByteIntConverter : ValueConverter

Would you please clarify for me, is the AdditionalTypeConverterFolder supposed to point to the TypeConverter, or the ValueConverter?

shannonm
User
Posts: 9
Joined: 08-Aug-2019
# Posted on: 14-Nov-2019 22:48:02   

Also, I'm a little uncertain; judging by this error, it looks like the TypeConverter it is failing to load is getting its fully-qualified name from the ValueConverter type, even though the LLBL project XML specifies both the runtime converter and its designer. Do the names have to collide for it to work?

shannonm
User
Posts: 9
Joined: 08-Aug-2019
# Posted on: 14-Nov-2019 22:56:40   

Let me clarify my confusion a little. I assume the AdditionalTypeConverterFolder is supposed to point to the TypeConverter holding the converter's capabilities/designer definition, not the runtime implementation, because it looks like LLBL is trying to load the assembly. Except, it seems wrong then, that the error is:

A reference to the type converter Company.Data.Context.ByteIntConverter was found, however this typeconverter wasn't loaded / found.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Nov-2019 09:52:32   

JSStudz wrote:

Walaa wrote:

Your reply didn't specify whether you have tried what Otis suggested or not.

Please try to follow our suggestions and reply accordingly so we are clear what's going on at your side.

Please confirm that the current dll is compiled against the same .NET Framework version as that of the Designer used?

After doing so, please report back whether the types are loaded or not, in the designer, if you put the dll in the original folder, and open the Designer without loading any project. I've specified where to look at, to check the loaded types when the designer starts (so you need to close it first if it's already open and re-open it again).

I apologize, that was all sort of jumbled together, or my coffee didn't kick in yet. I see what the issue is then. Really not sure why the .Net standard 2.1 didn't pop out first for you guys. wink

I overlooked it as I didn't assume you had a netstandard2.1 type converter wink

But! let's not make things more confusing than they already are simple_smile I'll go over the info provided again and see what the problem is.

shannonm wrote:

Hey guys, working with JStudz on this. I'm new to LLBL but a little more familiar with the MS NET "Standard" mess. Yes, we are using EF Core 3.0. Given:

<Property Name="AdditionalTypeConverterFolder" Value=".\bin\debug\netstandard2.0\" />

<FieldMapping FieldName="RowVersion" TargetFieldName="RowVersion" TypeConverterToUse="Company.Data.Context.ByteIntConverter" />

<TypeConversionDefinitions>
<TypeConversionDefinition TypeConverter="Company.Core.TypeConverters.ByteIntConverterCapabilities" DbDotNetType="System.Byte[]" FilterDbType="21" />
</TypeConversionDefinitions>

where:

ByteIntConverterCapabilities : TypeConverter
ByteIntConverter : ValueConverter

Would you please clarify for me, is the AdditionalTypeConverterFolder supposed to point to the TypeConverter, or the ValueConverter?

To the TypeConverter. All type converters in the designer should be deriving from TypeConverter. 'ValueConverter' is a type from the EFCore assembly and that's not recognized/supported in the designer. The typeconverter type is used to define a 'type conversion' in the mappings. When you then generate code the type ends up being defined as a conversion on the field in the EF Core code. As the name is the same, you can just reference your ValueConverter variant in your EF Core code and it should work.

So to recap: for every type converter you want to use, you have to have a: - variant deriving from TypeConverter, this is the one used in the designer. It's enough to implement the CanConvertFrom/To and CreateInstance methods. - variant deriving from ValueConverter, this is the one used in the EF Core code at runtime. - The names of the types have to be the same, as well as the namespaces. - Store the TypeConverter types in one assembly and the ValueConverter types in another.

shannonm wrote:

Also, I'm a little uncertain; judging by this error, it looks like the TypeConverter it is failing to load is getting its fully-qualified name from the ValueConverter type, even though the LLBL project XML specifies both the runtime converter and its designer. Do the names have to collide for it to work?

Yes, as the names are generated into the EF Core code. The designer variants are just to tell the designer 'this is the conversion needed, and it converts between type A and B' and the designer will then use that type in the code output to define that conversion for EF Core for you. If the type names aren't the same the EFCore code refers to a type that doesn't exist at runtime.

It's a confusing mess, I'm aware. We sadly can't do much else than this, as EFCore went .net core only and we cant' reference these types. This is also the reason we added as much type converters as possible to match the set of conversions defined in EF Core itself.

That said, I see you're using a Byte <-> Int converter. EF Core has implicit value conversions for numeric types, so converting byte <-> int isn't strictly necessary.

shannonm wrote:

Let me clarify my confusion a little. I assume the AdditionalTypeConverterFolder is supposed to point to the TypeConverter holding the converter's capabilities/designer definition, not the runtime implementation, because it looks like LLBL is trying to load the assembly. Except, it seems wrong then, that the error is:

A reference to the type converter Company.Data.Context.ByteIntConverter was found, however this typeconverter wasn't loaded / found.

Yes this error is correct, as you stated above:

where:

ByteIntConverterCapabilities : TypeConverter
ByteIntConverter : ValueConverter

So the 'ByteIntConverter' is the ValueConverter one.

Try to keep them in separate assemblies (you don't need to define new code if you don't want to, you can link files in a csproj as well. You can then e.g. define a compiler directive to be used in an #ifdef in one of the projects to derive from valueconverter and the other from typeconverter)


The conversions you're trying to use, what are they exactly? Perhaps they fall under the 'implicit numeric conversions' already supported and you can skip the converters altogether simple_smile

Frans Bouma | Lead developer LLBLGen Pro
shannonm
User
Posts: 9
Joined: 08-Aug-2019
# Posted on: 15-Nov-2019 16:13:40   

RE: the types used by the converter, the conversion is between ROWVERSION and and INT, to provide client concurrency and data message order resolution. (note it's a byte array)

Thanks so much for the clarification. I see, I see. We'll get right on trying it out. Jamie had a solution in-play before our EFCore 3.0 upgrade, but it was confusing to come back to with the name collision.

Yes, I agree the current solution is confusing... as long as you have an alternate folder and understand you may have a stand-in, why not allow specification of the type name for its capabilities provider? The name collision made it especially hard to understand what what happening or supposed to be happening. Not a big deal, since you guys were so helpful in explaining, but just a thought.

It was bad of MS to deadend NETFX on such short notice, when "The .NET Standard is a formal specification of .NET APIs that are intended to be available on all .NET implementations. The motivation behind the .NET Standard is establishing greater uniformity in the .NET ecosystem."

It was bad of MS to choose to do it on a minor version (2.0 -> 2.1) change, adding confusion.

Also, yeah, it was pretty freaking rude of EFCore team to decide to blast over to NETSTANDARD2.0 without considering breaking changes. They realized their mistake and 3.1 will go back to 2.0, effectively hurting the few people who did the work to get C# 8 features out of it. All a disaster of epic proportions. But what can we expect from the company who thought rebuilding EF from the ground up 5 years ago, with the expectation everyone wants to store all their relational data schema including complex SQL logic in C# attributes, was a good idea?

We don't blame LLBL for any of that! smile

shannonm
User
Posts: 9
Joined: 08-Aug-2019
# Posted on: 15-Nov-2019 20:24:29   

Yes, that assistance solved it for us, thank you! Stay warm out there!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 18-Nov-2019 09:45:49   

shannonm wrote:

Thanks so much for the clarification. I see, I see. We'll get right on trying it out. Jamie had a solution in-play before our EFCore 3.0 upgrade, but it was confusing to come back to with the name collision.

Yes, I agree the current solution is confusing... as long as you have an alternate folder and understand you may have a stand-in, why not allow specification of the type name for its capabilities provider? The name collision made it especially hard to understand what what happening or supposed to be happening. Not a big deal, since you guys were so helpful in explaining, but just a thought.

The type name isn't sufficient as the designer needs to verify which converter can convert things. Which means it has to actually call the CanConvertFrom/To methods. With a type name it can't, and more importantly: it can't automatically assign type converters. The designer supports type conversion definitions (see project settings) where you can define conversions between types using type converters and filters, and the designer can automatically apply these. With just a typename it can't do that.

It was bad of MS to deadend NETFX on such short notice, when "The .NET Standard is a formal specification of .NET APIs that are intended to be available on all .NET implementations. The motivation behind the .NET Standard is establishing greater uniformity in the .NET ecosystem."

yeah tell me about it disappointed First months of work and frustration to port things to ns 1.6 which in the end failed as it was so limited, then the introduced ns2.0 which shuold have been introduced way earlier and then they EOL'd .net framework. I contributed the DbProviderFactories implementation to .NET Core but due to their own slowness (it took more than a year!) I missed the ns2.0 deadline so it basically became useless as everyone had to implement a workaround for .net core 2.0 (as we did too with RuntimeConfiguration) to register the DbProviderFactory anyway.

Also, yeah, it was pretty freaking rude of EFCore team to decide to blast over to NETSTANDARD2.0 without considering breaking changes. They realized their mistake and 3.1 will go back to 2.0, effectively hurting the few people who did the work to get C# 8 features out of it.

Interesting, didn't know that! Will look into this, as it's a change we have to anticipate on too. Thanks for the heads up simple_smile

All a disaster of epic proportions. But what can we expect from the company who thought rebuilding EF from the ground up 5 years ago, with the expectation everyone wants to store all their relational data schema including complex SQL logic in C# attributes, was a good idea?

smile yeah sometimes I wonder what the end goal is for them. I mean, they now ported EF 6.3 to netstandard 2.0, so it runs on .net core, so going forward will they keep both EF 6 and EF Core or ditch one after a while? It's like a vote of no confidence against their own work (ef core).

We don't blame LLBL for any of that! smile

smile

Frans Bouma | Lead developer LLBLGen Pro