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.
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"/>…
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
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.
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.
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.
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
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.
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.
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.
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.
RockfordLhotka:
Is your criteria class nested in your business class?
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?
RockfordLhotka:
It is quite possible that you've got some code in your class that blocks serialization and is somehow causing this exception.
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?
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?
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
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