Can't register for COM! Please help.

Posts   
 
    
Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 20-Aug-2008 11:41:55   

Hi,

I'm working on a migration from LLBLGen 1.0.2005.1 to 2.6, because we face unacceptable performance now. I have the LLBLGen Pro 2.6 Final DEMO from august 14th.

This is the thread I initially started: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=14076

I have done a lot of refactoring now. I set everything up to use Remoting and the FastSerializer. The server-side looks good so far.

But now that I have set up everthing the way I want I run into an unforseen problem:

Some parts of the client software needs access to the generated code through COM. Therefore we register the generated code libraries for COM using REGASM.

This was no problem before, because there were no generics used. But now the generated code uses generics for a lot of properties. Examples:

public virtual Nullable<System.Int32> MapId
public virtual EntityCollection<Pdb101ArtikelenEntity> Pdb101Artikelen

REGASM will produce warnings and the Nullable and Collection properties are not exposed to COM anymore. This is a huge problem for us, because a lot of our code depends on this. If this is not going to work, we will not be able to migrate to LLBLGen 2.6 and we won't be able to benefit from the optimizations and FastSerializer.

Please advise.

Thanks, Rene Lergner

Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 20-Aug-2008 13:35:15   

I tought I'd take a long shot. I copied the entityAdapter.template and entityIncludeAdapter.template from the .NET1.1 folder (.NET1.1 does not use generics) and copied them over the templates for .NET2.0. As I suspected, that didn't end well. 1065 errors in my generated code. Too many dependencies across the projects.

Is there any other way to use the part of the .NET1.1 templates that do not use the generics and continue to use the .NET2.0 framework and LLBLGen 2.6 runtimes?? Any other suggestions??

Thanks, Rene Lergner

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 20-Aug-2008 14:32:09   

It's hard to get hold of these different worlds.

Either drop COM and use modern communication techniques..like WCF & Webservices with .NET 2.0+ Or stick to .NET 1.x Or create a COM wrapper around the LLBLGen stuff.

The nullable stuff can be surpressed but the entitycollection<T> stuff can't. that the generics make COM go bezerk is logical, it can't do runtime code emitting but if you want to consume the code through COM, it will be a hard struggle due to the generics.

Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 20-Aug-2008 14:57:40   

Hi Walaa,

I only use COM to communicate between the Client-applications and the Client-libraries. The client-libraries are in .NET and they provide proxies for Remoting, WCF, ASMX webservices or whatever transport I'd like to use. We use REGASM to create a COM-wrapper for the client-libraries to let the application use them. So it's not a choice to between COM and another transport-layer, COM wraps our transport-layer.

Before we used: LLBLGen 1.0.2005.1, .NET 2.0 and SQL Server on the server side. We created a webreference in a .NET 2.0 client-library, which contains the proxies. Then create a COM-wrapper for that. This works, but it does not perform well.

The applications we built are very slowly moving towards .NET. Part of it is the Data Access Layes which is now .NET 2.0 and LLBLGen. The applications have a very large codebase (over a million lines of code wink ). So we are not able to port that all to .NET in order to have generics on the client-side.

But we have this performance challenge (see other thread) and you suggest we upgrade to LLBLGen 2.6. So I'm trying that now. I have multiple branches of our codebase. 2 of them use LLBLGen 2.6 (demo) now. One of them implements Remoting (with FastSerializer) and the other implements WCF with DataContractFormat and netTcpBinding. Those should be the fastest implementations. This is all very nice, but our client-applications still need to consume this over COM, one way or the other.

We never used .NET 1.1. It has always been .NET 2.0 or higher. It's just that LLBLGen 1.0.2005.1 doesn't use generics, so we were able to make COM wrappers. Now that we try to move to LLBLGen 2.6 (still with .NET 2.0 / 3.0) we can't seem to make COM wrappers anymore. That we use WCF or Remoting, instead of ASMX-webservices doesn't even matter. What matters is that we can't use generics on the client-side (because of the COM wrappers), eventhough we use .NET 2.0.

So what we really want is all the goods from LLBLGen 2.6, but the EntityCollection properties declared as non-generics in the templates.

There are a few possible angles, but I guess they are somewhat difficult to implement. I will try to grab all templates from LLBLGen 2.6 for .NET 1.1 except for the project-files. So that we will be able to keep the references to the .NET 2.0 framework and LLBLGen 2.6 and still use Visual Studio 2005.

Any help or suggestions for a smart implemention are welcome! Thanks, Rene Lergner

Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 20-Aug-2008 15:40:51   

rage @#%$@#$#@#@% rage

That didn't work either. Because The EntityCollection in the generated code (taken from generated code for .NET 1.1) inherrits EntityCollectionBase2 from the SupportClasses. But we link the supportclasses for .NET 2.0 now. In those runtimes the EntityCollectionBase2 is a generic type, so it can't be inherrited by non-generic EntityCollection. It give a compile-error. It is only possible when I use the runtimes for .NET 1.1, but that will also use the .NET framework 1.1.

As I stated before, we NEED this to be accessible through COM. But as I see this now, the only way to upgrade to LLBLGen 2.6 is to downgrade to .NET 1.1 and Visual Studio 2003. This is not an option. I really hope someone has a brilliant idea, how to use proxies without generics, or we're screwed. confused cry frowning

Thanks, Rene Lergner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 20-Aug-2008 16:13:45   

I'd like to start with the unpleasant remark that the problems you're facing won't go away till you drop either COM or the .NET part. Com interop is a tough subject and often a land of problems, so although MS markets it as a nice way of writing software, the marriage between COM and .NET isn't good. The generics problems will likely not go away as we spend a lot of time in making code generic in v2!

That said, you could try with a custom template and replace the EntityCollection<T> usage with the EntityCollection class. This class is also in the generated code and is non-generic (effectively it's an EntityCollectionBase2<EntityBase2> class)

The template you should look at is entityIncludeAdapter.template in Templates\SharedTemplates\Net2.x\C#

Then look for "EntityCollection<" and replace the usage with EntityCollection(factory) in instantiation instances and make casts work otherwise. This will make sure the entity has no generics to the outside and which might make it work in COM. I say "might", as we don't guarantee the o/r layer to work in a COM app, as com-interop is too fragile and buggy to support such a layer.

Frans Bouma | Lead developer LLBLGen Pro
Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 21-Aug-2008 00:47:10   

Hi Frans,

Thanks alot! That worked! I actually get entities over the wire now (LLBLGen 2.6 / .NET 2.0 / Remoting / FastSerializing / COM-interop).

I admit COM-interop is a real pain now and then. But until now we got things working. And we don't even have a choice either. We maintain old code and migrate to .NET as much as possible. But we're talking about a huge amount of code here, so it's a long process. And in the mean time the two worlds have to communicate through COM.

Well, as I said, COM-interop can be a pain in the ### sometimes. Just as I'm experiencing right now. Just as I thought everything was compiling and working and receiving an entitycollection with contents etc, I have a runtime-error.

It seems the EntityCollection.Count property is hidden for COM-interop. The reason is beyond my comprehension. Does anyone have an idea why this happens? I can access the "Item" and "Capacity" properties through COM, but "Count" is gone with the wind...

Any suggestions would be appreciated! Thanks, Rene Lergner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 21-Aug-2008 10:42:37   

The only difference I can find between Capacity and Count is that Capacity is writable, and Count isn't. They're in the same base class.

If you add a partial class to EntityCollection and add public new int Count { get { return base.Count;} set { int v = value;} }

and test that, does it then pop up?

Frans Bouma | Lead developer LLBLGen Pro
Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 21-Aug-2008 14:53:25   

Hi Frans,

Thanks for your help. But unfortunately that doesn't work. I've been investigating this all day. I discovered one reason why I can't get the Count from an EntityCollection, but there is something else that prevents it and I can't seem to find out what it is. I will try to explain shortly. Maybe someone who reads it may know what's happening.

First let me explain why I can't read the Count from the EntityCollection through COM:

In COM it is not possible to use generics. So I changed the templates for the entities, so it wouldn't use EntityCollection<TEntity>. I also ran a plug-in in the LLBLGen designer to disable all nullable types, which also use generics. So now I use EntityCollection. The inheritance tree looks like this:

  • HelperClasses.EntityCollection: EntityCollectionNonGeneric
    • ORMSupportClasses.EntityCollectionNonGeneric: EntityCollectionBase2<EntityBase2>
      • ORMSupportClasses.EntityCollectionBase2<TEntity>: CollectionCore<TEntity>, IEntityCollection2
        • ORMSupportClasses.CollectionCore<T>

The Count-property, which is not visible in COM, is in CollectionCore. The Capacity-property, which is visible in COM, is in EntityCollectionBase2<TEntity> (as implementation of IEntityCollection2), but also in CollectionCore<T>. The Capacity-property that is visible in COM is the one from EntityCollectionBase2<TEntity> and not from CollectionCore<T>, because everything in CollectionCore<T> is hidden for COM. The reason is that when EntityCollectionBase2<EntityBase2> is inherited by EntityCollectionNonGeneric, it is not inherited as a generic type, because the type (EntityBase2) is defined as constant-type. When CollectionCore<TEntity> is inherited by EntityCollectionBase2<TEntity> it is hidden, because TEntity is the generic type.

So Count is hidden, because it is generic inheritance (not because it is read-only, that's no problem). Still, Frans' solution should work then (by adding an implementation of the Count-property to EntityCollection), but it doesn't.

It is not working, because for some strange reason, the EntityCollection-class is exported to COM as completly transparent type!

Everything I try to change (add or remove) is not visible in the version of EntityCollection that is exposed to COM. I checked and double-checked all paths and references to make sure I'm not importing old binaries or type-libraries. That's not the problem. Also I can see, that all classes that expose EntityCollection are casted to EntityCollectionNonGeneric in my COM-wrapper. That's probably the reason why I don't get a Count-property when I add it to EntityCollection. It seems that during the COM-registration-process the EntityCollection is 'downcasted' to EntityCollectionNonGeneric and it cannot be 'upcasted' anymore. I really don't understand why this behaviour occurs.

I try to rename (refactor) EntityCollection<TEntity> to EntityCollectionGeneric<TEntity> in an attempt to prevent the COM-exporter to get confused with the generic version of EntityCollection, but that did not have any result to the castings.

Right now, I'm stuck there. Hopefully someone can shine a light on this matter.

Frans, I'm sorry for all your hard work on the generics, that I now try to undo stuck_out_tongue_winking_eye But I really need to do this.

Thanks, Rene Lergner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 21-Aug-2008 16:08:25   

If your entities now expose EntityCollection typed properties, I don't know why it picks the baseclass of that type instead of EntityCollection for com.

I also don't understand why some stuff doesn't turn up in COM and other things do...

I don't think I can help you further...

Frans Bouma | Lead developer LLBLGen Pro
Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 21-Aug-2008 18:03:56   

Hi Frans,

Maybe you can help me out anyway. I have a sneaking suspicion that this odd behaviour of the com-wrapper is caused by the ToolboxItem(true) attribute of the EntityCollectionNonGeneric class.

Would it be possible to generate a test build for me with this attribute removed?

Thanks! Rene Lergner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 21-Aug-2008 18:05:21   

Rene wrote:

Hi Frans,

Maybe you can help me out anyway. I have a sneaking suspicion that this odd behaviour of the com-wrapper is caused by the ToolboxItem(true) attribute of the EntityCollectionNonGeneric class.

Would it be possible to generate a test build for me with this attribute removed?

Thanks! Rene Lergner

heh, that would be really silly. I'll build one, just a sec.

(edit) attached.

Frans Bouma | Lead developer LLBLGen Pro
Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 22-Aug-2008 00:51:31   

Hi again,

You're absolutely right. That would be silly. But I investigated all logical explanations and only less logical explanations were left to try. Thanks for the very fast response. I tried the test-build of the runtime, but unfortunately it didn't work. It thought it might work, because I googled for the words "RegAsm", "inheritance" and "ToolboxItem" and I did find a topic about and issue with RegAsm, not being able to wrap a derived type, because of the ToolboxItem-attibute. And sounded familiar to me.

Anyway, I investigated further. And I did some disturbing discoveries. To sumarize:

  1. All exposed types that share an inheritance tree will be casted to the smallest common ancester (base-class) that is exposed to COM (in my case that is EntityCollectionNonGeneric).
  2. If types share a common base type that is not exposed to COM (because it is a generic type) it is possible that one of the types is first upcasted to that common base class and then downcasted to a different derived type that is exposable to COM. frowning
  3. Any exposed type will only expose one of the interfaces it inherits from (probably the last in the list of interfaces that are exposable to COM).
  4. The members it exposes to COM will be inherited up to the point where generic inheritance starts.

Now for the work-around. From the EntityCollection I actually only need "Items" and "Count" in the COM-part of our app. So I created an Interface that defines those properties. I added the Interface to EntityCollection and implemented those properties in the EntityCollection-class (I need to modify the templates for this, but that is not much work). Now, when I look in the exported EntityCollection I only see the Count and Items property (explained in point 3). When I get an collection from LLBLGen it will be an EntityCollectionNonGeneric (explained in point 1) and it has no Count-property (explained in point 4). But I am allowed to cast this EntityCollectionNonGeneric to EntityCollection in COM and I can access the Items and the Count like I wanted to! sunglasses

I'm still not finished with the migration to LLBLGen 2.6 / FastSerializer, because in the initial tests I just did I still got some invalid casts etc at runtime, which are probably due to the breaking changes between 1.0.2005.1 and 2.6. But I'm still confident I can manage to get it working. When I've done that I need to do performance test to see what I gained and if things are acceptable. Really hope so! stuck_out_tongue_winking_eye

This issue is solved. Thanks for all the support! smile Rene Lergner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 22-Aug-2008 10:06:20   

Whoa, that sounds like a true nightmare scenario! frowning

What you should keep in mind though, is that software maintenance is a key factor here. Your route to make this work sounds challenging, but can be a burden over time, till there's serious planning done when COM is dropped OR that everything NOT com is moved to COM.

I also find it a bit odd that the wrapper code uses 1 interface only. This sounds like they (MS) wanted to make teh com stuff just work with VB5/6 and that's it, as COM is perfectly capable to deal with multiple interfaces, you just have to ask for the right interface.

Frans Bouma | Lead developer LLBLGen Pro
Rene
User
Posts: 54
Joined: 20-Jun-2006
# Posted on: 22-Aug-2008 10:26:45   

You're right. Software maintenance is really difficult in this project. I document the research I did for internal use and the steps I did are easy to reproduce now. I also modified the templates, so updating the project is no problem.

... OR that everything NOT com is moved to COM

Do I hear you say that you're gonna port LLBLGen to VB6?? smile Hahaha! Well, the idea is to move everything to .NET. But our programming-capacity is limited. We also have to develop new features (preferably in C# but also in VB6 when necessary) and maintain old code (bugfixing).

So we moved the DAL to .NET now (part LLBLGen and part custom remoting services). Also some of the business layer and little parts of the client software is .NET now. But this is a huge amount of code (many years of development), so it might take a few more years before we moved everything to C# managed code. We cannot plan for dropping COM now. It's a long process. We just have to handle this with care for the time being.

I did a lot of COM-interop in the past, but I didn't run into problems like these before. We didn't encounter such multiple-inheritance trees, including generics. But I learned alot from it and the next time I encounter this I know how to handle it.

I also find it a bit odd that the wrapper code uses 1 interface only. This sounds like they (MS) wanted to make teh com stuff just work with VB5/6 and that's it, as COM is perfectly capable to deal with multiple interfaces, you just have to ask for the right interface

I totally agree. The interfaces are flattened for COM-interop, but it could be done alot more intuitive. They should have made this commandline RegAsm for the quick-fixes and a more extended tool with GUI for the more complex cases, like we face. But I don't think MS is going to, because COM is a thing of the past. It would only encourage people to keep their old code and IDE instead of moving forward.

Rene Lergner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 22-Aug-2008 10:48:53   

VB6 is something looooooong forgotten here, no, I won't do anything with that anymore. simple_smile

COM isn't dead btw, most Microsoft code is still COM / C++ / win32 based, and that will be the case for many many years to come. Though I think the COM as it is used in VB6 is indeed dead, as well as for line of business apps.

Good luck with your adventures through interop land simple_smile

Frans Bouma | Lead developer LLBLGen Pro