Using 2 dataportals

Using 2 dataportals

Old forum URL: forums.lhotka.net/forums/t/4472.aspx


steve981 posted on Friday, March 07, 2008

Hi, I have the following exeption:

"Soap Serializer does not support serializing Generic Types : BusinessList `2+Criteria[BusinessList, BusinessEntity]."


It is an application, which is using a business object through a Data Portal using remoting. The Data Access layer of the business object calls another business object, which uses another Data Portal using remoting. The second business object is the one that raises the exception.

Right now both dataportals are in my localhost, but the idea is to put them in different physical machines to access different servers.

How can the second invocation to the business object be supported?  I appreciate you help.  All suggestions are welcome.  Note that everything is done on WinXP PC (both the application and the data portals; which are using IIS/HTTP).

The web.config  of the application is:

  <appSettings>

    <add key="CslaAuthentication" value="Windows" />

    <add key="CslaDataPortalProxy"

    value="Csla.DataPortalClient.RemotingProxy, Csla"/>

    <add key="CslaDataPortalUrl"

    value="http://localhost/WebSiteDataPortal/RemotingPortal.rem"/>

  </appSettings>

 

The web.config  of the first  Data Portal is:

  <appSettings>

    <add key="CslaAuthentication" value="Windows" />

    <add key="CslaDataPortalProxy"

    value="Csla.DataPortalClient.RemotingProxy, Csla"/>

    <add key="CslaDataPortalUrl"

    value="http://localhost/DataPortalServer/RemotingPortalServer.rem"/>

  </appSettings>

  <connectionStrings>

    <add name="ConnString" connectionString="Data Source=MyServer;Initial  Catalog=Database;uid=test;pwd=test;" providerName="System.Data.SqlClient"/>

  </connectionStrings>

  <system.runtime.remoting>

    <application>

      <service>

        <wellknown mode="SingleCall" objectUri="RemotingPortal.rem"

        type="Csla.Server.Hosts.RemotingPortal, Csla"/>

      </service>

      <channels>

        <channel ref="http">

          <serverProviders>

            <provider ref="wsdl"/>

            <formatter ref="soap" typeFilterLevel="Full"/>

            <formatter ref="binary" typeFilterLevel="Full"/>…

 

The web.config  of the second  Data Portal is:

  <appSettings>

    <add key="CslaAuthentication" value="Windows" />

  </appSettings>

  <connectionStrings>

    <add name="ConnString" connectionString="Data Source=SecondServer;Initial Catalog=Database;uid=test;pwd=test;" providerName="System.Data.SqlClient"/>

  </connectionStrings>

  <system.runtime.remoting>

    <application>

      <service>

        <wellknown mode="SingleCall" objectUri="RemotingPortalServer.rem"

        type="Csla.Server.Hosts.RemotingPortal, Csla"/>

      </service>

      <channels>

        <channel ref="http">

          <serverProviders>

            <provider ref="wsdl"/>

            <formatter ref="soap" typeFilterLevel="Full"/>

            <formatter ref="binary" typeFilterLevel="Full"/>…


Regards,

Steven Walker


tmg4340 replied on Friday, March 07, 2008

From the error you're getting, I don't think this is a CSLA issue - this is a .NET issue.

What it looks like you've done is create a generic Criteria class - something like this (in C# form):

private class Criteria<C, T>

Unfortunately, if you intend to send something like this "over the wire", it won't work.  The XML serializers don't know how to handle open generic types, which is what your criteria class is.  I think the issue is that the serializer doesn't know how to properly represent the generic parameters in what would essentially be a run-time situation.  But that's purely a guess.

In order to serialize this via XML, you have to create a subclass of your generic type - something like this:

private class Criteria2 : Criteria<BusinessList, BusinessEntity>

This creates a closed generic type, which the XML serializers can handle.  I know it doesn't look any different than creating the type in your routine call, but it is.

I realize that probably creates an issue for you, since the whole point of creating the generic criteria class was for re-use.  But it's the only way I know of to get the types to seralize.

Another option would be to investigate using WCF, which uses a newer set of serialization classes.  But I can't guarantee that this issue is resolved there, so you might end up right back here.

HTH

- Scott

steve981 replied on Friday, March 07, 2008

Thanks a lot for your quick reply, but I'm not using a generic Criteria class. The following is my Criteria implementation:
        [Serializable()]
        protected class Criteria
        {  
            public string CriteriaInfo;
            public int Code;
            public ArrayList Parameters = new ArrayList();
        }

However, I'm using generic business objects to allow inheritance as shown in http://forums.lhotka.net/forums/thread/1181.aspx

    [Serializable()]
    public abstract class BusinessList<T, C> : BusinessListBase<T, C>
        where T : BusinessList<T, C>
        where C : BusinessEntity<C>
    {...}


Could this be the problem?

The tricky part of this is that is goes just fine through the first dataportal, is the second one that raises the exception.

Regards,
Steven Walker

boo replied on Friday, March 07, 2008

I have a similiar problem, and you get the error because at location of the first data portal I assume there isn't the object that is in the second data portal.

I've been waiting to see if anyone will respond to my post about need assembly A on remote portal on machine A and assembly B on remote portal on machine B but application X uses both assembly A and B; but I haven't had a response yet.

I'll be watching this thread too though - I think it will really just take some customization of the CSLA core framework though because I don't think Rocky's intention was to support multiple remote data portals...I don't think it would be hard to do, but I can see why Rocky would've left that out of the main features - it's a rabbit hole.

My basic thought would be that the appSettings would have to be replaced by an actual configuration file, and part of that configuration file would be for it to have a default portal and a 'usePortalForAssembly' section where it had an assembly, and portal settings...that way the DataPortal object would say, this 'object' is part of X assembly - no overrides, so use default Portal, this 'object' is part of Y assembly, 'usePortalForAssembly' entry present, use 'that' Portal.

But I'm sure it's not that simple.  And unfortunately for us, we can't just arbritrarily make a change to CSLA and implement it in production overnight.

tmg4340 replied on Friday, March 07, 2008

boo:
I have a similiar problem, and you get the error because at location of the first data portal I assume there isn't the object that is in the second data portal.

That seems like an odd condition to create the SOAP error.  The error message doesn't say it can't find a type - it says it can't serialize an open generic type.

The criteria class is not an open generic type, but it's containing type is, which may be what's causing the problems.  Again, I realize that this will likely cause headaches, but given the error, I might try moving the criteria class out of the base class.  I'm not saying it's a solution, but it's something to try to see whether that resolves the error.

boo:
I've been waiting to see if anyone will respond to my post about need assembly A on remote portal on machine A and assembly B on remote portal on machine B but application X uses both assembly A and B; but I haven't had a response yet.

Based on the way remoting works, I would expect that the answer to your question is that assemblies A and B have to exist on both machines that host your data portal.

boo:
I'll be watching this thread too though - I think it will really just take some customization of the CSLA core framework though because I don't think Rocky's intention was to support multiple remote data portals...I don't think it would be hard to do, but I can see why Rocky would've left that out of the main features - it's a rabbit hole.

My basic thought would be that the appSettings would have to be replaced by an actual configuration file, and part of that configuration file would be for it to have a default portal and a 'usePortalForAssembly' section where it had an assembly, and portal settings...that way the DataPortal object would say, this 'object' is part of X assembly - no overrides, so use default Portal, this 'object' is part of Y assembly, 'usePortalForAssembly' entry present, use 'that' Portal.

Chaining data portals is not necessarily a difficult situation to contend with, and I wouldn't expect there to be much need for changes in CSLA to accommodate that.  But maybe I'm not following what you're after, since I don't see a whole lot of benefit to matching data portals to assemblies.  Unless you want to route to a different data portal based on the type of object being sent... is that what you're talking about?  Because I think you could probably get that by implementing your own data portal proxy.

Presuming that's what you're after - which I think is different than what Steven is contending with - that, in theory, could change my answer about where assemblies need to be located.  I would probably still put both assemblies on both data portal boxes, just in case.  But it may not be an absolute requirement.  It depends on assembly references and such.

- Scott

RockfordLhotka replied on Sunday, March 09, 2008

tmg4340:

Chaining data portals is not necessarily a difficult situation to contend with, and I wouldn't expect there to be much need for changes in CSLA to accommodate that.  But maybe I'm not following what you're after, since I don't see a whole lot of benefit to matching data portals to assemblies.  Unless you want to route to a different data portal based on the type of object being sent... is that what you're talking about?  Because I think you could probably get that by implementing your own data portal proxy.

I think what boo is trying to do is chain data portals without having the business assembly on each tier (client, dataportal A, dataportal B). That won't work though, because .NET deserializes the message on each tier, and that means the assemblies must be present. This isn't really CSLA, as much as the way Remoting or WCF work.

I think you might be able to do a fancy solution in WCF. It might be possible to create a custom data portal channel where you write message-level code (instead of service-level code) in WCF to get the inbound message before it is deserialized in dataportal A. Then you'd have to be able to figure out how to route the message without deserializing the data, so any routing info would have to be in the SOAP header, not the payload.

You couldn't do that with Remoting unless you wrote your own Remoting channel, because Remoting doesn't have (to my knowledge) an extensibility point to let you get the raw message byte stream prior to deserialization - so this is a low-level WCF thing only.

Certainly it isn't anything I plan to do in core CSLA.

RockfordLhotka replied on Sunday, March 09, 2008

Back to Steve's original post - that is an odd exception.

Is your criteria class nested in your business class?

I know people do some other things, but there are only two supported models for criteria: it must be a nested class, or it must subclass CriteriaBase. Any other technique could fail, and is not supported.

If you follow those rules, there's no problem even using a generic criteria class. CSLA .NET 3.5 actually includes a new generic criteria class that eliminates the need to create the majority of custom criteria classes.

boo replied on Sunday, March 09, 2008

This is what I'm trying to do - I was getting this similiar error because I had a reference to one assembly that used a remote portal, but I also had a reference to another assembly that didn't use the remote portal - when I made calls to that assembly it was trying to find it on the remote machine where it didn't exist (because of the settings to use  a remote machine for the other referenced assembly) and thus I got the errror.  I didn't get this exact error - I got a 'Type not found' serialization exception; but the situation seemed similiar to what I was trying to do.

http://forums.lhotka.net/forums/thread/21910.aspx

Marcos replied on Saturday, March 08, 2008

I Changed CreateBusinessObject in SimpleDataPortal like this to support Generics

        ' get the type of the actual business object
        ' based on the nested class scheme in the book
                businessType = criteria.GetType.DeclaringType
                'Code Added To Support Generics
                If businessType.IsGenericTypeDefinition Then
                    Dim l As New List(Of Type)
                    For Each arg As Type In criteria.GetType.GetGenericArguments
                        l.Add(arg)
                    Next
                    Return Activator.CreateInstance(businessType.MakeGenericType(l.ToArray), True)

                Else
                    Return Activator.CreateInstance(businessType, True)
                End If

      End If

 

Hoop this helps.

RockfordLhotka replied on Sunday, March 09, 2008

steve981:

Hi, I have the following exeption:

"Soap Serializer does not support serializing Generic Types : BusinessList `2+Criteria[BusinessList, BusinessEntity]."

I guess what I find most odd about this is that it appears you are somehow using the deprecated SoapFormatter. The data portal uses the BinaryFormatter. Are you possibly using a custom data portal channel, or has someone changed the core CSLA code?

Since the SoapFormatter is deprecated, I suppose it is quite possible that it doesn't support generics. I can't say, as I haven't tried using it for many years.

The BinaryFormatter can have some issues with generic types if they are the top-level object being serialized. However, the data portal never passes your types directly - they are always wrapped in some container (data portal context object, data portal result object, etc).

One think you can do is try to use Clone() to clone your object. Just to see if the BinaryFormatter can serialize/deserialize your object - without the data portal involved. Create an instance of your object (probably with some children in the list) and clone it. It is quite possible that you've got some code in your class that blocks serialization and is somehow causing this exception.

steve981 replied on Monday, March 10, 2008

RockfordLhotka:


Is your criteria class nested in your business class?


Yes, actually it is.

RockfordLhotka:


I guess what I find most odd about this is that it appears you are somehow using the deprecated SoapFormatter. The data portal uses the BinaryFormatter. Are you possibly using a custom data portal channel, or has someone changed the core CSLA code?


The CSLA core remains the same, and I have no idea why it is using the SoapFormatter.

RockfordLhotka:


It is quite possible that you've got some code in your class that blocks serialization and is somehow causing this exception.


I don't think so, since it successfully passes through the first dataportal, it is the second one that raises the exception.

RockfordLhotka replied on Monday, March 10, 2008

steve981:

I don't think so, since it successfully passes through the first dataportal, it is the second one that raises the exception.

OK, I want to be clear, because I'm now confused.

boo wants to just use two different data portals - one for one set of objects and another for a different set of objects. That's something that can be accomplished with a custom client-side data portal proxy and is a matter for a different thread.

Am I right that you are trying to chain data portals, so the client calls a data portal, and that just calls another data portal?

steve981 replied on Monday, March 10, 2008

RockfordLhotka:

Am I right that you are trying to chain data portals, so the client calls a data portal, and that just calls another data portal?



Exactly... The object goes through the first dataportal, while on the server it calls itself (or other business object) and try to go to another dataportal, but here it fails.

stanc replied on Monday, March 10, 2008

I tried to do something similiar to have a local cache server. I was going to have the call go to the local server first and if the object was available in the cache return it, otherwise make another dataportal call to get the information. I never could get this to work because of security issue. Basically the second call would fail because it never had permissions to remote to the other server, because it could not pass along that it was me. I believe Rocky was the one who pointed this out, and basically there was no way around it.

Maybe like Rocky said, you may be able to figure something out using WCF.

Good luck and please update the post if you find a resonable solution.

-stan

RockfordLhotka replied on Monday, March 10, 2008

Oh, well certainly if you are using Windows authentication and impersonation you are done before you get started. That is a limitation of Windows impersonation that is very well documented on MSDN and elsewhere – impersonation can only go one hop across the network.

 

I somehow though we were talking about custom authentication here, and I don’t know of a reason why that wouldn’t work.

 

Rocky

 

 

From: stanc [mailto:cslanet@lhotka.net]
Sent: Monday, March 10, 2008 9:32 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Using 2 dataportals

 

I tried to do something similiar to have a local cache server. I was going to have the call go to the local server first and if the object was available in the cache return it, otherwise make another dataportal call to get the information. I never could get this to work because of security issue. Basically the second call would fail because it never had permissions to remote to the other server, because it could not pass along that it was me. I believe Rocky was the one who pointed this out, and basically there was no way around it.

Maybe like Rocky said, you may be able to figure something out using WCF.

Good luck and please update the post if you find a resonable solution.

-stan



Copyright (c) Marimer LLC